
Il dataset in oggetto proviene dal governo del Regno Unito, che ha raccolto e pubblicato informazioni dettagliate sugli incidenti stradali in tutto il paese dal 2004 al 2017. Queste informazioni includono, ma non sono limitate a, posizioni geografiche, condizioni meteorologiche, tipo di veicoli, numero di vittime e manovre dei veicoli, rendendo questo un dataset molto interessante e completo per l'analisi e la ricerca.
Il dataset è stato scaricato dal sito Kaggle dal seguente link: https://www.kaggle.com/datasets/tsiaras/uk-road-safety-accidents-and-vehicles?select=Vehicle_Information.csv. A sua volta i dati provengono dal sito Web Open Data del governo del Regno Unito, dove sono stati pubblicati dal Dipartimento dei trasporti.
L'obiettivo principale di questo progetto è risolvere il seguente task:
Task: date le informazioni su caratteristiche di un incidente (es. condizioni della strada, condizioni metereologiche, condizioni del guidatore, ecc.), predire la gravità che avrà quell'incidente (Accident_Severity).
La soluzione fornita qui è progettata per essere una soluzione autonoma. Quindi non vi è alcun requisito in merito alla compatibilità o integrazione con altri modelli.
Il modo migliore per affrontare il problema è quello di utilizzare un approccio di apprendimento supervisionato, con qualche algoritmo di classificazione binaria.
Il resto del progetto è suddiviso nei seguenti capitoli:
Il codice seguente è scritto in Python 3.x. Le librerie forniscono funzionalità per eseguire le attività necessarie.
#load packages
import sys
import pickle
print("Python version: {}". format(sys.version))
import pandas as pd
print("pandas version: {}". format(pd.__version__))
pd.set_option('display.max_columns', None)
import matplotlib
print("matplotlib version: {}". format(matplotlib.__version__))
import numpy as np
print("NumPy version: {}". format(np.__version__))
import scipy as sp
print("SciPy version: {}". format(sp.__version__))
import IPython
from IPython import display
print("IPython version: {}". format(IPython.__version__))
import sklearn
print("scikit-learn version: {}". format(sklearn.__version__))
#misc libraries
import random
import time
import calendar
#ignore warnings
import warnings
warnings.filterwarnings('ignore')
print('-'*25)
#Imbalanced learning
from imblearn.under_sampling import RandomUnderSampler
from imblearn.under_sampling import NearMiss
#Transformer
from sklearn.pipeline import Pipeline
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.preprocessing import FunctionTransformer
from sklearn.cluster import KMeans
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OrdinalEncoder
from sklearn.preprocessing import OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import RobustScaler
from collections import Counter
#Common Model Algorithms
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.naive_bayes import BernoulliNB
from sklearn.naive_bayes import GaussianNB
from sklearn.neighbors import KNeighborsClassifier
from sklearn.neural_network import MLPClassifier
from sklearn.svm import SVC
from sklearn.linear_model import SGDClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import VotingClassifier
from sklearn.ensemble import AdaBoostClassifier
#import xgboost as xgb
#from xgboost import XGBClassifier
#from sklearn import svm, tree, linear_model, neighbors, naive_bayes, ensemble, discriminant_analysis, gaussian_process
#Common Model Helpers
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder, LabelEncoder, OrdinalEncoder
from sklearn.model_selection import GridSearchCV
#Visualization
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.pylab as pylab
import seaborn as sns
from itertools import cycle
#from pandas.tools.plotting import scatter_matrix
#Configure Visualization Defaults
#%matplotlib inline = show plots in Jupyter Notebook browser
%matplotlib inline
mpl.style.use('ggplot')
sns.set_style('white')
pylab.rcParams['figure.figsize'] = 12,8
#check cartelle
from subprocess import check_output
print(check_output(["ls", "./input"]).decode("utf8"))
print(check_output(["ls", "./img"]).decode("utf8"))
Python version: 3.9.12 (main, Apr 5 2022, 06:56:58) [GCC 7.5.0] pandas version: 1.4.2 matplotlib version: 3.5.1 NumPy version: 1.21.5 SciPy version: 1.7.3 IPython version: 8.2.0 scikit-learn version: 1.0.2 ------------------------- Accident_Information.csv Vehicle_Information.csv carcrash.jpg features_importance.png nearmiss.png PROGETTO.ipynb prova.png uk.png
Il dataset è composto da due file CSV:
I due file/set di dati sopra menzionati possono essere collegati tramite l'identificatore univoco dell'incidente stradale (colonna Accident_Index).
Più in dettaglio ecco spiegato brevemente il significato degli attributi dei due dataset:
Per quanto riguarda AccidentInformation.csv:
Per quanto riguarda Vehicle_Information.csv:
(*) Questo è l'attributo che si vuole predire
Si importano i due dataset con pandas: Accident_Information e Vehicle_information.
accidents = pd.read_csv('./input/Accident_Information.csv')
print('Records:', accidents.shape[0], '\nColumns:', accidents.shape[1])
accidents.head()
Records: 2047256 Columns: 34
| Accident_Index | 1st_Road_Class | 1st_Road_Number | 2nd_Road_Class | 2nd_Road_Number | Accident_Severity | Carriageway_Hazards | Date | Day_of_Week | Did_Police_Officer_Attend_Scene_of_Accident | Junction_Control | Junction_Detail | Latitude | Light_Conditions | Local_Authority_(District) | Local_Authority_(Highway) | Location_Easting_OSGR | Location_Northing_OSGR | Longitude | LSOA_of_Accident_Location | Number_of_Casualties | Number_of_Vehicles | Pedestrian_Crossing-Human_Control | Pedestrian_Crossing-Physical_Facilities | Police_Force | Road_Surface_Conditions | Road_Type | Special_Conditions_at_Site | Speed_limit | Time | Urban_or_Rural_Area | Weather_Conditions | Year | InScotland | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 200501BS00001 | A | 3218.0 | NaN | 0.0 | Serious | None | 2005-01-04 | Tuesday | 1.0 | Data missing or out of range | Not at junction or within 20 metres | 51.489096 | Daylight | Kensington and Chelsea | Kensington and Chelsea | 525680.0 | 178240.0 | -0.191170 | E01002849 | 1 | 1 | 0.0 | 1.0 | Metropolitan Police | Wet or damp | Single carriageway | None | 30.0 | 17:42 | Urban | Raining no high winds | 2005 | No |
| 1 | 200501BS00002 | B | 450.0 | C | 0.0 | Slight | None | 2005-01-05 | Wednesday | 1.0 | Auto traffic signal | Crossroads | 51.520075 | Darkness - lights lit | Kensington and Chelsea | Kensington and Chelsea | 524170.0 | 181650.0 | -0.211708 | E01002909 | 1 | 1 | 0.0 | 5.0 | Metropolitan Police | Dry | Dual carriageway | None | 30.0 | 17:36 | Urban | Fine no high winds | 2005 | No |
| 2 | 200501BS00003 | C | 0.0 | NaN | 0.0 | Slight | None | 2005-01-06 | Thursday | 1.0 | Data missing or out of range | Not at junction or within 20 metres | 51.525301 | Darkness - lights lit | Kensington and Chelsea | Kensington and Chelsea | 524520.0 | 182240.0 | -0.206458 | E01002857 | 1 | 2 | 0.0 | 0.0 | Metropolitan Police | Dry | Single carriageway | None | 30.0 | 00:15 | Urban | Fine no high winds | 2005 | No |
| 3 | 200501BS00004 | A | 3220.0 | NaN | 0.0 | Slight | None | 2005-01-07 | Friday | 1.0 | Data missing or out of range | Not at junction or within 20 metres | 51.482442 | Daylight | Kensington and Chelsea | Kensington and Chelsea | 526900.0 | 177530.0 | -0.173862 | E01002840 | 1 | 1 | 0.0 | 0.0 | Metropolitan Police | Dry | Single carriageway | None | 30.0 | 10:35 | Urban | Fine no high winds | 2005 | No |
| 4 | 200501BS00005 | Unclassified | 0.0 | NaN | 0.0 | Slight | None | 2005-01-10 | Monday | 1.0 | Data missing or out of range | Not at junction or within 20 metres | 51.495752 | Darkness - lighting unknown | Kensington and Chelsea | Kensington and Chelsea | 528060.0 | 179040.0 | -0.156618 | E01002863 | 1 | 1 | 0.0 | 0.0 | Metropolitan Police | Wet or damp | Single carriageway | None | 30.0 | 21:13 | Urban | Fine no high winds | 2005 | No |
accidents.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 2047256 entries, 0 to 2047255 Data columns (total 34 columns): # Column Dtype --- ------ ----- 0 Accident_Index object 1 1st_Road_Class object 2 1st_Road_Number float64 3 2nd_Road_Class object 4 2nd_Road_Number float64 5 Accident_Severity object 6 Carriageway_Hazards object 7 Date object 8 Day_of_Week object 9 Did_Police_Officer_Attend_Scene_of_Accident float64 10 Junction_Control object 11 Junction_Detail object 12 Latitude float64 13 Light_Conditions object 14 Local_Authority_(District) object 15 Local_Authority_(Highway) object 16 Location_Easting_OSGR float64 17 Location_Northing_OSGR float64 18 Longitude float64 19 LSOA_of_Accident_Location object 20 Number_of_Casualties int64 21 Number_of_Vehicles int64 22 Pedestrian_Crossing-Human_Control float64 23 Pedestrian_Crossing-Physical_Facilities float64 24 Police_Force object 25 Road_Surface_Conditions object 26 Road_Type object 27 Special_Conditions_at_Site object 28 Speed_limit float64 29 Time object 30 Urban_or_Rural_Area object 31 Weather_Conditions object 32 Year int64 33 InScotland object dtypes: float64(10), int64(3), object(21) memory usage: 531.1+ MB
plt.figure(figsize=(15,5))
s = pd.Series(accidents.isnull().sum()/accidents.shape[0]).sort_values(ascending=False)
sns.barplot(x = s.index, y = s.values)
plt.xticks(rotation=90)
plt.title("Valori nulli nelle features in percentuale", size=20)
Text(0.5, 1.0, 'Valori nulli nelle features in percentuale')
Si nota come la maggior parte dei valori sono di tipo object, ovvero categorici; inoltre in questo grafico a barre sono evidenziate le features che in percentuale rispetto al numero totale di righe, hanno un numero considerevole di valori null.
vehicles = pd.read_csv('./input/Vehicle_Information.csv', encoding='ISO-8859-1')
print('Records:', vehicles.shape[0], '\nColumns:', vehicles.shape[1])
vehicles.head()
Records: 2177205 Columns: 24
| Accident_Index | Age_Band_of_Driver | Age_of_Vehicle | Driver_Home_Area_Type | Driver_IMD_Decile | Engine_Capacity_.CC. | Hit_Object_in_Carriageway | Hit_Object_off_Carriageway | Journey_Purpose_of_Driver | Junction_Location | make | model | Propulsion_Code | Sex_of_Driver | Skidding_and_Overturning | Towing_and_Articulation | Vehicle_Leaving_Carriageway | Vehicle_Location.Restricted_Lane | Vehicle_Manoeuvre | Vehicle_Reference | Vehicle_Type | Was_Vehicle_Left_Hand_Drive | X1st_Point_of_Impact | Year | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 200401BS00001 | 26 - 35 | 3.0 | Urban area | 4.0 | 1588.0 | None | None | Data missing or out of range | Data missing or out of range | ROVER | 45 CLASSIC 16V | Petrol | Male | None | No tow/articulation | Did not leave carriageway | 0.0 | Going ahead other | 2 | 109 | Data missing or out of range | Front | 2004 |
| 1 | 200401BS00002 | 26 - 35 | NaN | Urban area | 3.0 | NaN | None | None | Data missing or out of range | Data missing or out of range | BMW | C1 | NaN | Male | None | No tow/articulation | Did not leave carriageway | 0.0 | Going ahead other | 1 | 109 | Data missing or out of range | Front | 2004 |
| 2 | 200401BS00003 | 26 - 35 | 4.0 | Data missing or out of range | NaN | 998.0 | None | None | Data missing or out of range | Data missing or out of range | NISSAN | MICRA CELEBRATION 16V | Petrol | Male | None | No tow/articulation | Did not leave carriageway | 0.0 | Turning right | 1 | 109 | Data missing or out of range | Front | 2004 |
| 3 | 200401BS00003 | 66 - 75 | NaN | Data missing or out of range | NaN | NaN | None | None | Data missing or out of range | Data missing or out of range | LONDON TAXIS INT | TXII GOLD AUTO | NaN | Male | None | No tow/articulation | Did not leave carriageway | 0.0 | Going ahead other | 2 | 109 | Data missing or out of range | Front | 2004 |
| 4 | 200401BS00004 | 26 - 35 | 1.0 | Urban area | 4.0 | 124.0 | None | None | Data missing or out of range | Data missing or out of range | PIAGGIO | VESPA ET4 | Petrol | Male | None | No tow/articulation | Did not leave carriageway | 0.0 | Going ahead other | 1 | Motorcycle 125cc and under | Data missing or out of range | Front | 2004 |
vehicles.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 2177205 entries, 0 to 2177204 Data columns (total 24 columns): # Column Dtype --- ------ ----- 0 Accident_Index object 1 Age_Band_of_Driver object 2 Age_of_Vehicle float64 3 Driver_Home_Area_Type object 4 Driver_IMD_Decile float64 5 Engine_Capacity_.CC. float64 6 Hit_Object_in_Carriageway object 7 Hit_Object_off_Carriageway object 8 Journey_Purpose_of_Driver object 9 Junction_Location object 10 make object 11 model object 12 Propulsion_Code object 13 Sex_of_Driver object 14 Skidding_and_Overturning object 15 Towing_and_Articulation object 16 Vehicle_Leaving_Carriageway object 17 Vehicle_Location.Restricted_Lane float64 18 Vehicle_Manoeuvre object 19 Vehicle_Reference int64 20 Vehicle_Type object 21 Was_Vehicle_Left_Hand_Drive object 22 X1st_Point_of_Impact object 23 Year int64 dtypes: float64(4), int64(2), object(18) memory usage: 398.7+ MB
plt.figure(figsize=(15,5))
s = pd.Series(vehicles.isnull().sum()/vehicles.shape[0]).sort_values(ascending=False)
sns.barplot(x = s.index, y = s.values)
plt.xticks(rotation=90)
plt.title("Valori nulli nelle features in percentuale", size=20)
Text(0.5, 1.0, 'Valori nulli nelle features in percentuale')
Si nota come la maggior parte dei valori sono di tipo object, inoltre in questo grafico a barre sono evidenziate le features che in percentuale rispetto al numero totale di righe, hanno un numero considerevole di valori null.
Si visualizzano alcune informazioni sulla distribuzione delle features:
accidents.describe().T
| count | mean | std | min | 25% | 50% | 75% | max | |
|---|---|---|---|---|---|---|---|---|
| 1st_Road_Number | 2047254.0 | 992.105099 | 1809.407936 | 0.000000 | 0.000000 | 118.000000 | 702.000000 | 9.999000e+03 |
| 2nd_Road_Number | 2029663.0 | 372.815342 | 1287.796383 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 9.999000e+03 |
| Did_Police_Officer_Attend_Scene_of_Accident | 2046978.0 | 1.202319 | 0.408194 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 3.000000e+00 |
| Latitude | 2047082.0 | 52.559780 | 1.445506 | 49.912941 | 51.485404 | 52.237583 | 53.455902 | 6.075754e+01 |
| Location_Easting_OSGR | 2047092.0 | 441446.210036 | 95496.198208 | 64950.000000 | 378063.500000 | 443050.000000 | 524298.250000 | 6.555400e+05 |
| Location_Northing_OSGR | 2047092.0 | 296885.465668 | 160527.257527 | 10290.000000 | 177756.750000 | 261183.500000 | 395610.000000 | 1.208800e+06 |
| Longitude | 2047081.0 | -1.410155 | 1.403532 | -7.516225 | -2.329610 | -1.362233 | -0.205260 | 1.762010e+00 |
| Number_of_Casualties | 2047256.0 | 1.345843 | 0.817963 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 9.300000e+01 |
| Number_of_Vehicles | 2047256.0 | 1.833525 | 0.715054 | 1.000000 | 1.000000 | 2.000000 | 2.000000 | 6.700000e+01 |
| Pedestrian_Crossing-Human_Control | 2044336.0 | 0.010417 | 0.135113 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 2.000000e+00 |
| Pedestrian_Crossing-Physical_Facilities | 2043696.0 | 0.751802 | 1.835289 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 8.000000e+00 |
| Speed_limit | 2047219.0 | 38.843597 | 14.147910 | 0.000000 | 30.000000 | 30.000000 | 50.000000 | 7.000000e+01 |
| Year | 2047256.0 | 2010.523806 | 3.765624 | 2005.000000 | 2007.000000 | 2010.000000 | 2014.000000 | 2.017000e+03 |
vehicles.describe().T
| count | mean | std | min | 25% | 50% | 75% | max | |
|---|---|---|---|---|---|---|---|---|
| Age_of_Vehicle | 1819056.0 | 7.108167 | 4.725886 | 1.0 | 3.0 | 7.0 | 10.0 | 111.0 |
| Driver_IMD_Decile | 1442393.0 | 5.387559 | 2.821651 | 1.0 | 3.0 | 5.0 | 8.0 | 10.0 |
| Engine_Capacity_.CC. | 1911344.0 | 2042.233961 | 1950.143170 | 1.0 | 1299.0 | 1598.0 | 1997.0 | 96000.0 |
| Vehicle_Location.Restricted_Lane | 2175888.0 | 0.107304 | 0.879964 | 0.0 | 0.0 | 0.0 | 0.0 | 9.0 |
| Vehicle_Reference | 2177205.0 | 1.553405 | 0.775248 | 1.0 | 1.0 | 1.0 | 2.0 | 91.0 |
| Year | 2177205.0 | 2010.934147 | 3.694375 | 2004.0 | 2008.0 | 2011.0 | 2014.0 | 2016.0 |
accidents.hist(bins=50, figsize=(20,15))
plt.show()
Già qui si possono fare alcune considerazioni, si nota come Longitude e Location_Easting_OSGR hanno circa la stessa distribuzione (molto correlati), così vale anche per Latitude e Location_Northing_OSGR. Questo perchè effettivamente sono due modi diversi di localizzare l'incidente, quindi alla fine hanno lo stesso scopo e perciò per la fase di ML verrà tenuta una solo delle due. Dagli altri grafici altre considerazioni possono essere che la maggior parte degli incidenti ha 0 morti, oppure che la maggior parte degli incidenti sono avvenuti in strade con limiti di velocità pari a 30 mph, ovvero 48 Km/h; quindi ci fa capire che sono avvenuti non in superstrade, a causa della presenza di più veicoli e caos nelle città. Inoltre si può vedere come il numero di incidenti totali sia sceso negli anni.
vehicles.hist(bins=50, figsize=(20,15))
plt.show()
In questo caso ad esempio si vede come negli anni il numero di veicoli coinvolti negli incidenti è aumentato.
Prima di dividere da subito il training set dal test set, abbiamo necessità di creare un solo dataset. Quindi effettuiamo una inner join tra i due dataset (accidents e vehicles), in modo tale da aumentare la granularità dei nostri dati, quindi avere non più un insieme di incidenti ma un insieme di veicoli coinvolti in incidenti (ad esempio possono esserci più veicoli coinvolti nello stesso incidente). In questo modo avremo più proprietà interessanti ovvero quelle relative ai veicoli.
print('Accidents:', accidents.shape)
print('Vehicles:', vehicles.shape)
dataset = pd.merge(vehicles, accidents, how="inner")
print('Dataset:', dataset.shape)
dataset.head()
Accidents: (2047256, 34) Vehicles: (2177205, 24) Dataset: (2058408, 56)
| Accident_Index | Age_Band_of_Driver | Age_of_Vehicle | Driver_Home_Area_Type | Driver_IMD_Decile | Engine_Capacity_.CC. | Hit_Object_in_Carriageway | Hit_Object_off_Carriageway | Journey_Purpose_of_Driver | Junction_Location | make | model | Propulsion_Code | Sex_of_Driver | Skidding_and_Overturning | Towing_and_Articulation | Vehicle_Leaving_Carriageway | Vehicle_Location.Restricted_Lane | Vehicle_Manoeuvre | Vehicle_Reference | Vehicle_Type | Was_Vehicle_Left_Hand_Drive | X1st_Point_of_Impact | Year | 1st_Road_Class | 1st_Road_Number | 2nd_Road_Class | 2nd_Road_Number | Accident_Severity | Carriageway_Hazards | Date | Day_of_Week | Did_Police_Officer_Attend_Scene_of_Accident | Junction_Control | Junction_Detail | Latitude | Light_Conditions | Local_Authority_(District) | Local_Authority_(Highway) | Location_Easting_OSGR | Location_Northing_OSGR | Longitude | LSOA_of_Accident_Location | Number_of_Casualties | Number_of_Vehicles | Pedestrian_Crossing-Human_Control | Pedestrian_Crossing-Physical_Facilities | Police_Force | Road_Surface_Conditions | Road_Type | Special_Conditions_at_Site | Speed_limit | Time | Urban_or_Rural_Area | Weather_Conditions | InScotland | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 200501BS00002 | 36 - 45 | 3.0 | Data missing or out of range | NaN | 8268.0 | None | None | Journey as part of work | Leaving roundabout | DENNIS | NaN | Heavy oil | Male | None | No tow/articulation | Did not leave carriageway | 0.0 | Slowing or stopping | 1 | Bus or coach (17 or more pass seats) | No | Nearside | 2005 | B | 450.0 | C | 0.0 | Slight | None | 2005-01-05 | Wednesday | 1.0 | Auto traffic signal | Crossroads | 51.520075 | Darkness - lights lit | Kensington and Chelsea | Kensington and Chelsea | 524170.0 | 181650.0 | -0.211708 | E01002909 | 1 | 1 | 0.0 | 5.0 | Metropolitan Police | Dry | Dual carriageway | None | 30.0 | 17:36 | Urban | Fine no high winds | No |
| 1 | 200501BS00003 | 26 - 35 | 5.0 | Urban area | 3.0 | 8300.0 | Parked vehicle | None | Journey as part of work | Not at or within 20 metres of junction | DENNIS | NaN | Heavy oil | Male | None | No tow/articulation | Did not leave carriageway | 0.0 | Going ahead right-hand bend | 1 | Bus or coach (17 or more pass seats) | No | Nearside | 2005 | C | 0.0 | NaN | 0.0 | Slight | None | 2005-01-06 | Thursday | 1.0 | Data missing or out of range | Not at junction or within 20 metres | 51.525301 | Darkness - lights lit | Kensington and Chelsea | Kensington and Chelsea | 524520.0 | 182240.0 | -0.206458 | E01002857 | 1 | 2 | 0.0 | 0.0 | Metropolitan Police | Dry | Single carriageway | None | 30.0 | 00:15 | Urban | Fine no high winds | No |
| 2 | 200501BS00004 | 46 - 55 | 4.0 | Urban area | 1.0 | 1769.0 | None | None | Other/Not known (2005-10) | Not at or within 20 metres of junction | NISSAN | ALMERA SE AUTO | Petrol | Female | None | No tow/articulation | Did not leave carriageway | 0.0 | Going ahead other | 1 | Car | No | Front | 2005 | A | 3220.0 | NaN | 0.0 | Slight | None | 2005-01-07 | Friday | 1.0 | Data missing or out of range | Not at junction or within 20 metres | 51.482442 | Daylight | Kensington and Chelsea | Kensington and Chelsea | 526900.0 | 177530.0 | -0.173862 | E01002840 | 1 | 1 | 0.0 | 0.0 | Metropolitan Police | Dry | Single carriageway | None | 30.0 | 10:35 | Urban | Fine no high winds | No |
| 3 | 200501BS00005 | 46 - 55 | 10.0 | Data missing or out of range | NaN | 85.0 | Kerb | None | Other/Not known (2005-10) | Not at or within 20 metres of junction | HONDA | NaN | Petrol | Male | Skidded | No tow/articulation | Did not leave carriageway | 0.0 | Going ahead other | 1 | Motorcycle 125cc and under | No | Front | 2005 | Unclassified | 0.0 | NaN | 0.0 | Slight | None | 2005-01-10 | Monday | 1.0 | Data missing or out of range | Not at junction or within 20 metres | 51.495752 | Darkness - lighting unknown | Kensington and Chelsea | Kensington and Chelsea | 528060.0 | 179040.0 | -0.156618 | E01002863 | 1 | 1 | 0.0 | 0.0 | Metropolitan Police | Wet or damp | Single carriageway | None | 30.0 | 21:13 | Urban | Fine no high winds | No |
| 4 | 200501BS00006 | 46 - 55 | 1.0 | Urban area | 4.0 | 2976.0 | None | None | Other/Not known (2005-10) | Not at or within 20 metres of junction | AUDI | A4 SPORT CABRIOLET AUTO | Petrol | Male | None | No tow/articulation | Did not leave carriageway | 0.0 | Moving off | 1 | Car | No | Did not impact | 2005 | Unclassified | 0.0 | NaN | 0.0 | Slight | None | 2005-01-11 | Tuesday | 1.0 | Data missing or out of range | Not at junction or within 20 metres | 51.515540 | Daylight | Kensington and Chelsea | Kensington and Chelsea | 524770.0 | 181160.0 | -0.203238 | E01002832 | 1 | 2 | 0.0 | 0.0 | Metropolitan Police | Wet or damp | Single carriageway | Oil or diesel | 30.0 | 12:40 | Urban | Raining no high winds | No |
Notiamo come alcuni veicoli erano riferiti ad incidenti non presenti nel dataset degli incidenti, perchè il nuovo dataset appena creato contiene 2058408 righe al posto di contenere tutte le righe del dataset dei veicoli (2177205). Inoltre notiamo che il numero di colonne totali del nuovo dataset è pari a 56 invece di 58 (somma colonne dataset incidenti e veicoli) perchè le colonne Accident_Index e Year sono state prese una sola volta.
A questo punto la prima cosa da fare è separare una porzione di dati di questo data set per andare a creare il test set finale. Mentre la restante parte farà parte del training set. Effettuiamo già adesso la divisione per evitare qualsiasi fenomeno di data snooping. La scelta del test_size è pari a 0.01; questa scelta anche se può sembrare troppo piccola, in realtà è necessaria perchè più avanti la dimensione del training set attraverso tutta la fase di preprocessing diminuirà drasticamente, quindi serviranno in questo momento più tuple nel training set.
train_set, test_set = train_test_split(dataset, test_size=0.01, random_state=42)
train_set.shape, test_set.shape
((2037823, 56), (20585, 56))
train_set.Accident_Severity.hist(figsize=(7,5))
<AxesSubplot:>
test_set.Accident_Severity.hist(figsize=(7,5))
<AxesSubplot:>
Si nota come le distribuzioni non sono variate, come quella per la classe target Accident_Severity.
In questo capitolo verranno effettuate alcune analisi esplorative sui dataset, per acquisire ulteriori conoscenze su questi dati, e quindi sugli incidenti avvenuti. Tale fase ricade più in un task di data analysis, per tale motivo si può dire che è una parte extra del progetto. Le analisi saranno effettuate su due dataset inziali (accients e vehicles).
Innanzitutto grazie agli attributi Longitude e Latitude si è in grado di geolocalizzare gli incidenti e quindi vedere la loro posizione sulla mappa. Da notare che sono presenti molti incidenti (raccolti in 13 anni), che se vengono graficati tutti, si noterebbe ad occhio la cartina geografica della Gran Bretagna! Una prima analisi può essere una visualizzazione della distribuzione degli incidenti nello spazio, grazie alle coordinate spaziali di ogni singolo incidente, si visualizzerà la posizione di ogni incidente:
accidents.plot(kind="scatter", x="Longitude", y="Latitude", alpha=0.4,
s=0.5,
figsize=(8,12),
sharex=False)
<AxesSubplot:xlabel='Longitude', ylabel='Latitude'>
Si nota come i più di 2 milioni di incidenti sono tanti, infatti l'insieme di tutti gli incidenti ricostruiscono proprio la forma della Gran Bretagna! Per essere più precisi e avere un migliore senso dell'orientamento si plottano i punti sopra la cartina geografica della Gran Bretagna:
ac2005 = accidents.loc[accidents["Year"] == 2005]
a, b, c, d = ac2005.Longitude.min(), ac2005.Longitude.max(), ac2005.Latitude.min(), ac2005.Latitude.max()
mymap = plt.imread("./img/uk.png")
box = [a+0.1,b+0.1, c, d-0.05]
plt.figure(figsize=(8, 12))
plt.scatter(
accidents.Longitude, accidents.Latitude,
alpha=0.5,
s=0.5,
c="#1f77b4"
)
plt.imshow(mymap, alpha=1, zorder=0, extent=box)
<matplotlib.image.AxesImage at 0x7fbb8c37c8e0>
L'immagine di background inserita corrisponde ad una cartina geografica del Regno Unito in cui sono messe in risalto le strade principali (soprattutto le autostrade); infatti si vede come i punti sono distribuiti lungo di esse (verso la Scozia (nord) si nota di più, perchè nel sud ci sono molti più incidenti visto la presenza di città metropolitane come Londra, Manchester, Birminghan, ecc.)
Come è variato il numero di incidenti negli anni?
df_byYear = pd.DataFrame(accidents.Year.value_counts().sort_index()).reset_index()
df_byYear.columns = ["Year", "Numero di incidenti"]
plot = sns.barplot(x="Year", y="Numero di incidenti", palette="rocket", data=df_byYear)
plot.get_yaxis().set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ',')))
plot.set_title("Numero di incidenti per ogni anno dal 2005 al 2016")
percentage = np.array(df_byYear[["Numero di incidenti"]]/accidents.shape[0] * 100)
patches = plot.patches
for i in range(len(patches)):
x = patches[i].get_x() + patches[i].get_width()/2
y = patches[i].get_height()+300
plot.annotate('{:.1f}%'.format(float(percentage[i])), (x, y), ha='center', fontsize=14)
Negli anni il numero di incidenti è diminuito; in particolare l'anno 2005 è stato l'anno con più incidenti, mentre il 2017 con meno incidenti. Segue la posizione degli incidenti sulla mappa dei due anni (2005 e 2017):
righe=1
colonne=2
f = plt.figure(figsize=(6*colonne,9*righe))
anno = 2005
for i in range(0, righe):
for j in range(0, colonne):
acc_Y = accidents.loc[accidents["Year"]==anno]
ax = plt.subplot2grid((righe, colonne), (i,j))
l = "Year = " + str(anno)
ax.scatter(
acc_Y.Longitude, acc_Y.Latitude,
alpha=0.5,
s=1,
label = l,
c= "#1f77b4"
)
ax.legend(markerscale=10)
anno += 12
plt.show()
Si nota come nell'anno 2005 sono presenti molti più punti rispetto il 2017.
f = plt.figure(figsize=(8,12))
plt.scatter(
accidents.Longitude, accidents.Latitude,
alpha=0.5,
s=0.05,
label = "Year = 2015",
c= "#1f77b4"
)
#Londra -> 51.513989036923775, -0.12972395492792754
#Birminghan -> 52.54076987914765, -1.8327262157805437
#Manchester -> 53.55411409487268, -2.2133829968685537
plt.annotate('Londra ', xy=(-0.129, 51.513), xytext=(-0.5, 50), xycoords='data',
arrowprops=dict(facecolor='red', shrink=0.05),
)
plt.annotate('Birminghan ', xy=(-1.83, 52.54), xytext=(0.58, 53.5), xycoords='data',
arrowprops=dict(facecolor='red', shrink=0.05),
)
plt.annotate('Manchester ', xy=(-2.21, 53.55), xytext=(-4.97, 54), xycoords='data',
arrowprops=dict(facecolor='red', shrink=0.05),
)
plt.legend(markerscale=10)
plt.show()
Sono state evidenziate le posizioni di alcune città importanti quali Londra, Manchester e Birminghan; e come si può vedere in queste posizioni (soprattutto Londra), gli incidenti sono molto più densi; dovuti proprio dal fatto che nelle città ci sono tantissimi veicoli in circolazione.
Si possono continuare le analisi spaziali identificando le autorità che sono intervenute in quei particolari incidenti, ovvero le contee in cui sono avvenuti gli incidenti. Queste si dividono per district e highway; di seguito sono mostrati i grafici delle prime 20 contee con maggiori incidenti per ciascuna delle due categorie; inoltre verranno evidenziati anche la loro posizione sulla mappa con diversi colori in modo tale da riconoscere effettivamente l'area di competenza della particolare contea.
f = plt.figure(figsize=(15,8))
df_byLAD = pd.DataFrame(accidents["Local_Authority_(District)"].value_counts().sort_index()).reset_index()
df_byLAD.columns = ["Local_Authority_(District)", "Numero di incidenti"]
df_byLAD = df_byLAD.sort_values(ascending=False, by=["Numero di incidenti"])[0:20]
plot = sns.barplot(x="Numero di incidenti", y="Local_Authority_(District)", palette="rocket", data=df_byLAD)
plot.get_xaxis().set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ',')))
plot.set_title("Numero di incidenti per autorità locale di distretto")
percentage = np.array(df_byLAD[["Numero di incidenti"]]/accidents.shape[0] * 100)
patches = plot.patches
for i in range(len(patches)):
y = patches[i].get_y() + patches[i].get_height()/1.5
x = patches[i].get_width()+1000
plot.annotate('{:.1f}%'.format(float(percentage[i])), (x, y), ha='center', fontsize=14)
f = plt.figure(figsize=(15,8))
df_byLA = pd.DataFrame(accidents["Local_Authority_(Highway)"].value_counts().sort_index()).reset_index()
df_byLA.columns = ["Local_Authority_(Highway)", "Numero di incidenti"]
df_byLA = df_byLA.sort_values(ascending=False, by=["Numero di incidenti"])[0:20]
plot = sns.barplot(x="Numero di incidenti", y="Local_Authority_(Highway)", palette="rocket", data=df_byLA)
plot.get_xaxis().set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ',')))
plot.set_title("Numero di incidenti per autorità locale di autostrada")
percentage = np.array(df_byLA[["Numero di incidenti"]]/accidents.shape[0] * 100)
patches = plot.patches
for i in range(len(patches)):
y = patches[i].get_y() + patches[i].get_height()/1.5
x = patches[i].get_width()+1400
plot.annotate('{:.1f}%'.format(float(percentage[i])), (x, y), ha='center', fontsize=14)
f = plt.figure(figsize=(16,12))
colors = [
"#FF0000", "#00FF00", "#0000FF", "#FFFF00", "#FF00FF", "#00FFFF", "#000000",
"#800000", "#008000", "#000080", "#808000", "#800080", "#008080", "#808080",
"#C00000", "#00C000", "#0000C0", "#C0C000", "#C000C0", "#00C0C0", "#C0C0C0",
"#400000", "#004000", "#000040", "#404000", "#400040", "#004040", "#404040",
"#200000", "#002000", "#000020", "#202000", "#200020", "#002020", "#202020",
"#600000", "#006000", "#000060", "#606000", "#600060", "#006060", "#606060",
"#A00000", "#00A000", "#0000A0", "#A0A000", "#A000A0", "#00A0A0", "#A0A0A0",
"#E00000", "#00E000", "#0000E0", "#E0E000", "#E000E0", "#00E0E0", "#E0E0E0",
]
localAuth = df_byLAD["Local_Authority_(District)"].values
ax = plt.subplot2grid((1, 2), (0,0))
ax.imshow(mymap, alpha=1, zorder=0, extent=box)
plt.title("Local_Authority_(District)")
for i in range(0, 20):
acc_LA = accidents.loc[accidents["Local_Authority_(District)"]==localAuth[i]]
ax.scatter(
acc_LA.Longitude, acc_LA.Latitude,
alpha=0.5,
s=1,
label = localAuth[i],
c=colors[i]
)
ax.legend(markerscale=10)
localAuth = df_byLA["Local_Authority_(Highway)"].values
ax2 = plt.subplot2grid((1, 2), (0,1))
ax2.imshow(mymap, alpha=1, zorder=0, extent=box)
plt.title("Local_Authority_(Highway)")
for i in range(0, 20):
acc_LA = accidents.loc[accidents["Local_Authority_(Highway)"]==localAuth[i]]
ax2.scatter(
acc_LA.Longitude, acc_LA.Latitude,
alpha=0.5,
s=1,
label = localAuth[i],
c=colors[i]
)
ax2.legend(markerscale=10)
plt.show()
Come varia il numero di incidenti per le diverse categorie stradali? (si rimanda al seguente link per capire meglio la classificazione delle strade nel Regno Unito: https://en.wikipedia.org/wiki/Road_hierarchy):
f = plt.figure(figsize=(10,5))
df_byR = pd.DataFrame(accidents['1st_Road_Class'].value_counts().sort_index()).reset_index()
df_byR.columns = ["1st_Road_Class", "Numero di incidenti"]
df_byR = df_byR.sort_values(ascending=False, by=["Numero di incidenti"])[0:20]
plot = sns.barplot(x="1st_Road_Class", y="Numero di incidenti", palette="rocket", data=df_byR)
plot.get_yaxis().set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ',')))
plot.set_title("Numero di incidenti per categoria di strada")
percentage = np.array(df_byR[["Numero di incidenti"]]/accidents.shape[0] * 100)
patches = plot.patches
for i in range(len(patches)):
x = patches[i].get_x() + patches[i].get_width()/2
y = patches[i].get_height()+5000
plot.annotate('{:.1f}%'.format(float(percentage[i])), (x, y), ha='center', fontsize=14)
La categoria con maggiori incidenti è la categoria A (45.3% degli incidenti), per capire bene di che tipologie di strade sono, vengono plottati sulla cartina gli incidenti avvenuti in strade di categoria A:
f = plt.figure(figsize=(8,12))
localAuth = df_byR["1st_Road_Class"].values
plt.imshow(mymap, alpha=1, zorder=0, extent=box)
plt.title("1st_Road_Class")
i=0
acc_R = accidents.loc[accidents["1st_Road_Class"]==localAuth[i]]
plt.scatter(
acc_R.Longitude, acc_R.Latitude,
alpha=0.5,
s=1,
label = localAuth[i],
c=colors[i]
)
plt.legend(markerscale=10)
plt.show()
Come si può vedere si ha un riscontro geografico delle strade di categoria A; mentre le Motorway che sarebbero le strade più importanti (con più di 3 corsie) hanno giustamente meno incidenti essendo di meno. Ecco gli incidenti avvenuti nelle Motorway:
f = plt.figure(figsize=(8,12))
localAuth = df_byR["1st_Road_Class"].values
plt.imshow(mymap, alpha=1, zorder=0, extent=box)
plt.title("1st_Road_Class")
#for i in range(len(localAuth)):
i=4
acc_R = accidents.loc[accidents["1st_Road_Class"]==localAuth[i]]
plt.scatter(
acc_R.Longitude, acc_R.Latitude,
alpha=0.5,
s=1,
label = localAuth[i],
c=colors[i]
)
plt.legend(markerscale=10)
plt.show()
In che tipo di strada avvengono maggiormente gli incidenti? (Road_Type):
f = plt.figure(figsize=(15,7))
df_byRT = pd.DataFrame(accidents['Road_Type'].value_counts().sort_index()).reset_index()
df_byRT.columns = ["Road_Type", "Numero di incidenti"]
df_byRT = df_byRT.sort_values(ascending=False, by=["Numero di incidenti"])[0:20]
plot = sns.barplot(x="Road_Type", y="Numero di incidenti", palette="rocket", data=df_byRT)
plot.get_yaxis().set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ',')))
plot.set_title("Numero di incidenti per tipo di strada")
percentage = np.array(df_byRT[["Numero di incidenti"]]/accidents.shape[0] * 100)
patches = plot.patches
for i in range(len(patches)):
x = patches[i].get_x() + patches[i].get_width()/2
y = patches[i].get_height()+10000
plot.annotate('{:.1f}%'.format(float(percentage[i])), (x, y), ha='center', fontsize=14)
In questo caso il numero maggiore di incidenti si ha per strade a singola carreggiata (74,6%) seguito da strade a doppia carreggiata (14,8%), seguito anche dalle rotatoie (6.7%) e cos' via... Si visualizza sulla cartina:
typeRoad = df_byRT["Road_Type"].values
righe=2
colonne=4
f = plt.figure(figsize=(8*colonne,12*righe))
k=0
for i in range(0, righe):
for j in range(0, colonne):
if k<len(typeRoad):
acc_R = accidents.loc[accidents["Road_Type"]==typeRoad[k]]
ax = plt.subplot2grid((righe, colonne), (i,j))
ax.imshow(mymap, alpha=1, zorder=0, extent=box)
ax.scatter(
acc_R.Longitude, acc_R.Latitude,
alpha=0.5,
s=0.5,
label = typeRoad[k],
c= colors[k]
)
ax.legend(markerscale=10)
k += 1
plt.show()
Caso interessante, gli incidenti avvenuti sulle rotatoie, geograficamente sono punti concentrati rispetto quelli avvenuti ad esempio nelle strade a singola carreggiata.
Come varia il numero di incidenti in base ai limiti di velocità? (Speed_Limit):
f = plt.figure(figsize=(15,7))
df_bySL = pd.DataFrame(accidents['Speed_limit'].value_counts().sort_index()).reset_index()
df_bySL.columns = ["Speed_limit", "Numero di incidenti"]
df_bySL = df_bySL.sort_values(ascending=False, by=["Numero di incidenti"])[0:20]
plot = sns.barplot(x="Speed_limit", y="Numero di incidenti", palette="rocket", data=df_bySL, order=df_bySL["Speed_limit"])
plot.get_yaxis().set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ',')))
plot.set_title("Numero di incidenti per limite di velocità")
percentage = np.array(df_bySL[["Numero di incidenti"]]/accidents.shape[0] * 100)
patches = plot.patches
for i in range(len(patches)):
x = patches[i].get_x() + patches[i].get_width()/2
y = patches[i].get_height()+10000
plot.annotate('{:.1f}%'.format(float(percentage[i])), (x, y), ha='center', fontsize=14)
Il 63.8% degli incidenti è avvenuto in strade con limite di velocità 30 mph, ossia circa 48 km/h; che non è una velocità elevata... Ma questo è dovuto proprio al fatto che tali limiti si trovano più in strade vicino le città e quindi con un numero molto più elevato di veicoli in circolazione.
Per rendersi conto meglio che strade con limiti di velocità più bassi sono nelle città o nei pressi delle città, rispetto le strade con alti limiti di velocità (es. 70 mph) che si trovano più distanti dalle metropoli (autostrade, ecc.); si plottano le due cartine con i due limiti di velocità (limite minimo e limite massimo):
righe=1
colonne=2
f = plt.figure(figsize=(8*colonne,12*righe))
acc_S = accidents.loc[accidents["Speed_limit"]==30]
ax = plt.subplot2grid((righe, colonne), (0,0))
ax.imshow(mymap, alpha=1, zorder=0, extent=box)
ax.scatter(
acc_S.Longitude, acc_S.Latitude,
alpha=0.5,
s=1,
label = "30 mph (48.28 km/h)",
c= colors[0]
)
ax.legend(markerscale=10)
acc_S = accidents.loc[accidents["Speed_limit"]==70]
ax = plt.subplot2grid((righe, colonne), (0,1))
ax.imshow(mymap, alpha=1, zorder=0, extent=box)
ax.scatter(
acc_S.Longitude, acc_S.Latitude,
alpha=0.5,
s=1,
label = "70 mph (112.65 km/h)",
c= colors[1]
)
ax.legend(markerscale=10)
plt.show()
Come volevasi dimostrare nella mappa a destra si notano molto di più le strade (autostrade), rispetto quella di sinistra. Ad esempio il centro di Londra è presente nella mappa a sinistra e non in quella in destra.
Come varia il numero di morti (Number_of_Casualties) al variare dei limiti di velocità? Ci si aspetta che per strade con limiti maggiori di velocità ci siano più morti. Si controllerà il numero di morti relativo, ovvero il rapporto della somma del numero di morti per il numero di incidenti raggruppati per limiti di velocità:
f = plt.figure(figsize=(15,7))
df_bySLM = accidents.groupby("Speed_limit", as_index=False).agg({"Number_of_Casualties": np.sum, "Accident_Index": np.size})
df_bySLM.columns = ["Speed_limit", "Numero di morti", "Numero di incidenti"]
df_bySLM['Numero di morti relativo'] = df_bySLM.apply(lambda row: row["Numero di morti"] / row["Numero di incidenti"], axis=1)
df_bySLM.sort_values(by=["Numero di morti relativo"], inplace=True, ascending=False)
plot = sns.barplot(x="Speed_limit", y="Numero di morti relativo", palette="rocket", data=df_bySLM, order=df_bySLM["Speed_limit"])
plot.get_yaxis().set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ',')))
plot.set_title("Numero di incidenti per limite di velocità")
percentage = np.array(df_bySLM[["Numero di morti relativo"]]/df_bySLM["Numero di morti relativo"].sum() * 100)
patches = plot.patches
for i in range(len(patches)):
x = patches[i].get_x() + patches[i].get_width()/2
y = patches[i].get_height()+0.005
plot.annotate('{:.1f}%'.format(float(percentage[i])), (x, y), ha='center', fontsize=14)
Come ci si aspettava, il numero di morti relativo si ha per strade con limiti di velocità più alti; proprio perchè all'aumentare delle velocità c'è più probabilità di morire in caso di incidente.
Dove si trovano i 10 incidenti con il maggior numero di morti e con il maggior numero di veicoli coinvolti (Number_of_Vehicles):
righe=1
colonne=2
f = plt.figure(figsize=(8*colonne,12*righe))
acc_casualties = accidents.sort_values(ascending=False, by=["Number_of_Casualties"])[0:10]
ax = plt.subplot2grid((righe, colonne), (0,0))
ax.imshow(mymap, alpha=1, zorder=0, extent=box)
ax.scatter(
acc_casualties.Longitude, acc_casualties.Latitude,
alpha=1,
s=5*acc_casualties["Number_of_Casualties"],
label = "Top 10 Incidenti con maggior numero di morti",
c= colors[0]
)
ax.plot(acc_casualties.Longitude.values[0], acc_casualties.Latitude.values[0], marker="o", markersize=20, markeredgecolor="red", markerfacecolor="green", label="MAX")
ax.legend(markerscale=1)
for i, txt in enumerate(acc_casualties.Number_of_Casualties.values):
ax.annotate(txt, (acc_casualties.Longitude.values[i]+0.2, acc_casualties.Latitude.values[i]+0.05), fontsize=14)
acc_vehicles = accidents.sort_values(ascending=False, by=["Number_of_Vehicles"])[0:10]
ax = plt.subplot2grid((righe, colonne), (0,1))
ax.imshow(mymap, alpha=1, zorder=0, extent=box)
ax.scatter(
acc_vehicles.Longitude, acc_vehicles.Latitude,
alpha=1,
s=5*acc_vehicles["Number_of_Vehicles"],
label = "Top 10 Incidenti con maggior numero di veicoli coinvolti",
c= colors[2]
)
ax.plot(acc_vehicles.Longitude.values[0], acc_vehicles.Latitude.values[0], marker="o", markersize=20, markeredgecolor="red", markerfacecolor="green", label="MAX")
ax.legend(markerscale=1)
for i, txt in enumerate(acc_vehicles.Number_of_Vehicles.values):
ax.annotate(txt, (acc_vehicles.Longitude.values[i]+0.2, acc_vehicles.Latitude.values[i]+0.05), fontsize=14)
plt.show()
print("Massimo numero di morti in un incidente:", acc_casualties.Number_of_Casualties.values[0])
print("Massimo numero di veicoli coinvolti in un incidente:", acc_vehicles.Number_of_Vehicles.values[0])
Massimo numero di morti in un incidente: 93 Massimo numero di veicoli coinvolti in un incidente: 67
Come è variato invece, il numero di morti negli anni:
f = plt.figure(figsize=(20,7))
df_byYearSev = accidents.groupby("Year", as_index=False).agg({"Number_of_Casualties": np.sum, "Accident_Index": np.size})
df_byYearSev.columns = ["Anno", "Numero di morti", "Numero di incidenti"]
df_byYearSev.sort_values(by=["Numero di incidenti"], inplace=True, ascending=False)
plot = sns.barplot(data=df_byYearSev.melt(id_vars='Anno', value_vars=['Numero di morti', 'Numero di incidenti']), x='Anno', y='value', hue='variable', palette="rocket")
plot.get_yaxis().set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ',')))
plot.set_title("Numero di incidenti/morti per ogni anno dal 2005 al 2016")
percentage = np.array(df_byYearSev[["Numero di morti"]]/accidents["Number_of_Casualties"].sum() * 100)
percentage = np.concatenate((percentage, np.array(df_byYearSev[["Numero di incidenti"]]/accidents.shape[0] * 100)))
patches = plot.patches
for i in range(len(patches)):
x = patches[i].get_x() + patches[i].get_width()/2
y = patches[i].get_height()+1000
plot.annotate('{:.1f}%'.format(float(percentage[i])), (x, y), ha='center', fontsize=14)
f = plt.figure(figsize=(20,7))
df_byYearSev['Numero di morti relativo'] = df_byYearSev.apply(lambda row: row["Numero di morti"] / row["Numero di incidenti"], axis=1)
df_byYearSev.sort_values(by=["Numero di morti relativo"], inplace=True, ascending=False)
plot = sns.barplot(x="Anno", y="Numero di morti relativo", palette="rocket", data=df_byYearSev)
plot.get_yaxis().set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ',')))
plot.set_title("Numero di morti relativo per ogni anno dal 2005 al 2016")
percentage = np.array(df_byYearSev[["Numero di morti relativo"]]/df_byYearSev["Numero di morti relativo"].sum() * 100)
patches = plot.patches
for i in range(len(patches)):
x = patches[i].get_x() + patches[i].get_width()/2
y = patches[i].get_height()+0.005
plot.annotate('{:.1f}%'.format(float(percentage[i])), (x, y), ha='center', fontsize=14)
Il numero di morti ha avuto un andamento quasi costante negli anni.
Come variano il numero di morti e di incidenti nei mesi?
accidents['Month'] = pd.DatetimeIndex(accidents['Date']).month
accidents['Month'] = accidents['Month'].apply(lambda x: calendar.month_abbr[x])
f = plt.figure(figsize=(20,7))
df_byMonth = accidents.groupby("Month", as_index=False).agg({"Number_of_Casualties": np.sum, "Accident_Index": np.size})
df_byMonth.columns = ["Mese", "Numero di morti", "Numero di incidenti"]
df_byMonth.sort_values(by=["Numero di incidenti"], inplace=True, ascending=False)
plot = sns.barplot(data=df_byMonth.melt(id_vars='Mese', value_vars=['Numero di morti', 'Numero di incidenti']), x='Mese', y='value', hue='variable', palette="rocket")
plot.get_yaxis().set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ',')))
plot.set_title("Numero di incidenti/morti per mesi dell'anno")
percentage = np.array(df_byMonth[["Numero di morti"]]/accidents["Number_of_Casualties"].sum() * 100)
percentage = np.concatenate((percentage, np.array(df_byMonth[["Numero di incidenti"]]/accidents.shape[0] * 100)))
patches = plot.patches
for i in range(len(patches)):
x = patches[i].get_x() + patches[i].get_width()/2
y = patches[i].get_height()+1000
plot.annotate('{:.1f}%'.format(float(percentage[i])), (x, y), ha='center', fontsize=14)
accidents.drop(labels='Month', axis=1, inplace=True)
Il mese di novembre è stato quello con maggiori incidenti, seguito da ottobre, luglio ecc.
Come variano il numero di morti e di incidenti nei giorni della settimana?
f = plt.figure(figsize=(20,7))
df_byWeek = accidents.groupby("Day_of_Week", as_index=False).agg({"Number_of_Casualties": np.sum, "Accident_Index": np.size})
df_byWeek.columns = ["Giorno", "Numero di morti", "Numero di incidenti"]
df_byWeek.sort_values(by=["Numero di incidenti"], inplace=True, ascending=False)
plot = sns.barplot(data=df_byWeek.melt(id_vars='Giorno', value_vars=['Numero di morti', 'Numero di incidenti']), x='Giorno', y='value', hue='variable', palette="rocket")
plot.get_yaxis().set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ',')))
plot.set_title("Numero di incidenti/morti per giorni della settimana")
percentage = np.array(df_byWeek[["Numero di morti"]]/accidents["Number_of_Casualties"].sum() * 100)
percentage = np.concatenate((percentage, np.array(df_byWeek[["Numero di incidenti"]]/accidents.shape[0] * 100)))
patches = plot.patches
for i in range(len(patches)):
x = patches[i].get_x() + patches[i].get_width()/2
y = patches[i].get_height()+3000
plot.annotate('{:.1f}%'.format(float(percentage[i])), (x, y), ha='center', fontsize=14)
Il giorno della settimana con più incidenti (e anche morti) è il venerdì; molto probabile perchè il venerdì ci sono più spostamenti dovuti per la fine settimana lavorativa.
Come variano il numero di morti e di incidenti nelle ore della giornata?
accidents['Time_Interval'] = pd.to_datetime(accidents['Time'])
accidents['Time_Interval'] = accidents['Time_Interval'].dt.strftime('%H')
f = plt.figure(figsize=(20,7))
df_byHour = accidents.groupby("Time_Interval", as_index=False).agg({"Number_of_Casualties": np.sum, "Accident_Index": np.size})
df_byHour.columns = ["Ora", "Numero di morti", "Numero di incidenti"]
df_byHour.sort_values(by=["Numero di incidenti"], inplace=True, ascending=False)
plot = sns.barplot(data=df_byHour.melt(id_vars='Ora', value_vars=['Numero di morti', 'Numero di incidenti']), x='Ora', y='value', hue='variable', palette="rocket")
plot.get_yaxis().set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ',')))
plot.set_title("Numero di incidenti/morti per ora del giorno")
percentage = np.array(df_byHour[["Numero di morti"]]/accidents["Number_of_Casualties"].sum() * 100)
percentage = np.concatenate((percentage, np.array(df_byHour[["Numero di incidenti"]]/accidents.shape[0] * 100)))
patches = plot.patches
for i in range(len(patches)):
x = patches[i].get_x() + patches[i].get_width()/2
y = patches[i].get_height()+1000
plot.annotate('{:.1f}%'.format(float(percentage[i])), (x, y), ha='center', fontsize=14)
accidents.drop(labels='Time_Interval', axis=1, inplace=True)
Il maggior numero di incidenti/morti si hanno nel pomeriggio; ancora una volta una possibile motivazione può essere la maggiore affluenza dei veicoli in quelle ore (molti escono da lavoro). Mentre nelle ore di notte si hanno meno incidenti, anche se in proporzione si ha un maggior numero di morti, questo può essere giustificato dal fatto che la notte è più probabile trovare persone che guidano in stato di ebbrezza.
Ulteriori analisi verranno effettuate nel Capitolo 4: Pre-Processing, sezione 4.2 Esplorazione delle features.
In questa fase, verrà prima di tutto ripulito il dataset originale, rimuovendo ad esempio tutti i valori null e outliers; effettuando anche un ribilanciamento del dataset. In un secondo momento invece si effetturà una feature selection per andare ad individuare un sottoinsieme delle colonne del dataset, che poi andranno a formare il dataset finale; ed infine nell'ultima parte verranno effettuate tutte quelle trasformazioni sui dati per rendere il dataset "appetibile" agli algoritmi di data mining.
Si ricorda che il dataset che si ha come riferimento è train_set, ovvero quello proveniente dal captolo 2 Preparazione dei dati; in cui è stato effettuato lo split del train e test set a partire dal dataset risultante dalla inner join di accidents e vehicles.
print('Training set:', train_set.shape)
train_set.head()
Training set: (2037823, 56)
| Accident_Index | Age_Band_of_Driver | Age_of_Vehicle | Driver_Home_Area_Type | Driver_IMD_Decile | Engine_Capacity_.CC. | Hit_Object_in_Carriageway | Hit_Object_off_Carriageway | Journey_Purpose_of_Driver | Junction_Location | make | model | Propulsion_Code | Sex_of_Driver | Skidding_and_Overturning | Towing_and_Articulation | Vehicle_Leaving_Carriageway | Vehicle_Location.Restricted_Lane | Vehicle_Manoeuvre | Vehicle_Reference | Vehicle_Type | Was_Vehicle_Left_Hand_Drive | X1st_Point_of_Impact | Year | 1st_Road_Class | 1st_Road_Number | 2nd_Road_Class | 2nd_Road_Number | Accident_Severity | Carriageway_Hazards | Date | Day_of_Week | Did_Police_Officer_Attend_Scene_of_Accident | Junction_Control | Junction_Detail | Latitude | Light_Conditions | Local_Authority_(District) | Local_Authority_(Highway) | Location_Easting_OSGR | Location_Northing_OSGR | Longitude | LSOA_of_Accident_Location | Number_of_Casualties | Number_of_Vehicles | Pedestrian_Crossing-Human_Control | Pedestrian_Crossing-Physical_Facilities | Police_Force | Road_Surface_Conditions | Road_Type | Special_Conditions_at_Site | Speed_limit | Time | Urban_or_Rural_Area | Weather_Conditions | InScotland | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1412192 | 2014074244006 | Data missing or out of range | 11.0 | Data missing or out of range | NaN | 1995.0 | None | None | Not known | Not at or within 20 metres of junction | BMW | 320 D SE TOURING | Heavy oil | Male | None | No tow/articulation | Did not leave carriageway | 0.0 | Parked | 2 | Car | No | Nearside | 2014 | Unclassified | 0.0 | NaN | 0.0 | Slight | None | 2014-08-18 | Monday | 1.0 | Data missing or out of range | Not at junction or within 20 metres | 53.388626 | Daylight | Warrington | Warrington | 369659.0 | 388075.0 | -2.457681 | E01012517 | 2 | 2 | 0.0 | 0.0 | Cheshire | Dry | Single carriageway | None | 30.0 | 15:49 | Urban | Fine no high winds | No |
| 2057144 | 201697UA05912 | 26 - 35 | 7.0 | Urban area | NaN | 1108.0 | None | None | Not known | Approaching junction or waiting/parked at junc... | FIAT | PANDA ACTIVE ECO | Petrol | Female | None | No tow/articulation | Did not leave carriageway | 0.0 | Going ahead other | 2 | Car | No | Did not impact | 2016 | B | 780.0 | Unclassified | 0.0 | Slight | None | 2016-12-26 | Monday | 1.0 | Give way or uncontrolled | T or staggered junction | 55.633989 | Darkness - lights lit | North Ayrshire | North Ayrshire | 224716.0 | 641342.0 | -4.786159 | NaN | 1 | 2 | 0.0 | 4.0 | Strathclyde | Wet or damp | Single carriageway | None | 30.0 | 21:31 | Urban | Fine no high winds | Yes |
| 1935690 | 201631D088016 | 21 - 25 | 8.0 | Data missing or out of range | NaN | 124.0 | None | None | Not known | Not at or within 20 metres of junction | KYMCO | KR SPORT 125 | Petrol | Male | None | No tow/articulation | Did not leave carriageway | 0.0 | Going ahead other | 1 | Motorcycle 125cc and under | No | Front | 2016 | Unclassified | 0.0 | NaN | 0.0 | Slight | None | 2016-05-08 | Sunday | 1.0 | Data missing or out of range | Not at junction or within 20 metres | 52.952462 | Daylight | Rushcliffe | Nottinghamshire | 473991.0 | 340022.0 | -0.900129 | E01028371 | 1 | 2 | 0.0 | 0.0 | Nottinghamshire | Dry | Single carriageway | None | 30.0 | 12:49 | Rural | Fine no high winds | No |
| 725183 | 2010620201503 | 21 - 25 | 12.0 | Urban area | NaN | 1124.0 | None | None | Other/Not known (2005-10) | Approaching junction or waiting/parked at junc... | PEUGEOT | 106 XL INDEPENDENCE | Petrol | Male | None | No tow/articulation | Did not leave carriageway | 0.0 | Changing lane to left | 1 | Car | No | Front | 2010 | A | 4118.0 | Unclassified | 0.0 | Slight | None | 2010-06-07 | Monday | 1.0 | Give way or uncontrolled | Slip road | 51.629302 | Daylight | Swansea | Swansea | 265610.0 | 194070.0 | -3.943080 | W01000744 | 1 | 2 | 0.0 | 0.0 | South Wales | Wet or damp | Dual carriageway | None | 30.0 | 16:40 | Urban | Raining + high winds | No |
| 2008176 | 2016471601947 | 46 - 55 | 2.0 | Urban area | 8.0 | 2199.0 | None | None | Not known | Approaching junction or waiting/parked at junc... | KIA | SORENTO KX-2 CRDI 4X4 | Heavy oil | Male | None | No tow/articulation | Did not leave carriageway | 0.0 | Waiting to go - held up | 2 | Car | No | Nearside | 2016 | A | 27.0 | A | 284.0 | Slight | None | 2016-04-03 | Sunday | 1.0 | Auto traffic signal | Crossroads | 50.842999 | Daylight | Arun | West Sussex | 502934.0 | 105854.0 | -0.539367 | E01031392 | 2 | 3 | 0.0 | 0.0 | Sussex | Dry | Dual carriageway | None | 40.0 | 08:03 | Rural | Fine no high winds | No |
Si effettua una copia dell'originale set di addestramento, che servirà dopo per effettuare la fit su una pipeline delle trasformazioni:
train_set_iniziale = train_set.copy()
Si rimuovono i duplicati (se presenti):
print("Prima -->", train_set.shape)
train_set.drop_duplicates(keep='first', inplace=True)
print("Dopo -->", train_set.shape)
Prima --> (2037823, 56) Dopo --> (2037823, 56)
Non erano presenti duplicati.
Adesso si eliminano features che contengono troppi valori null, visti nel grafico della sezione precedente, e riportati nel grafico sottostante per il training set:
plt.figure(figsize=(15,5))
s = pd.Series(train_set.isnull().sum()/train_set.shape[0]).sort_values(ascending=False)
sns.barplot(x = s.index, y = s.values)
plt.xticks(rotation=90)
plt.title("Valori nulli nelle features in percentuale", size=20)
Text(0.5, 1.0, 'Valori nulli nelle features in percentuale')
Però non sono solo questi i valori null; infatti sono presenti altri valori null che però non vengono catturati, siccome in realtà sono salvati come un valore categorico. Infatti il valore "Data missing or out of range" lo si può sostituire con il valore NaN, così da non trascurare tali valori null. Si crea una classe per un transformer che effettua la replace dei valori "Data missing or out of range" in np.NaN, che verrà inserito più avanti in una pipeline:
class ReplaceValuesTransformer(BaseEstimator, TransformerMixin):
def __init__(self,valueFrom, valueTo):
self.valueFrom=valueFrom
self.valueTo=valueTo
def transform(self,X,y=None):
return X.replace(self.valueFrom, self.valueTo)
def fit(self, X, y=None):
return self
#pipeline = Pipeline([
# ("replaceValuesToNan", replaceValuesTransformer("Data missing or out of range", np.NaN))
#])
replaceValuesToNan = ReplaceValuesTransformer('Data missing or out of range', np.NaN)
train_set = replaceValuesToNan.fit_transform(train_set)
Viene riportato il grafico aggiornato dei valori null:
plt.figure(figsize=(15,5))
s = pd.Series(train_set.isnull().sum()/train_set.shape[0]).sort_values(ascending=False)
sns.barplot(x = s.index, y = s.values)
plt.xticks(rotation=90)
plt.title("Valori nulli nelle features in percentuale", size=20)
Text(0.5, 1.0, 'Valori nulli nelle features in percentuale')
Si nota come sono comparsi attributi con molti valori null che prima erano sfuggiti, come l'attributo Junction_Control.
In particolare si effettua la drop delle seguenti colonne:
print("Prima -->", train_set.shape)
train_set.drop(labels='Driver_IMD_Decile', axis=1, inplace=True)
train_set.drop(labels='model', axis=1, inplace=True)
train_set.drop(labels='2nd_Road_Class', axis=1, inplace=True)
train_set.drop(labels='2nd_Road_Number', axis=1, inplace=True)
train_set.drop(labels='LSOA_of_Accident_Location', axis=1, inplace=True)
train_set.drop(labels='Junction_Control', axis=1, inplace=True)
print("Dopo -->", train_set.shape)
Prima --> (2037823, 56) Dopo --> (2037823, 50)
Si eliminano anche altre features che non sono di interesse per il task; ad esempio Date, oppure Location_Easting_OSGR e Location_Northing_OSGR perchè sono un altro modo per localizzare l'incidente (bastano Latitude e Longitude):
print("Prima -->", train_set.shape)
train_set.drop(labels='Date', axis=1, inplace=True)
train_set.drop(labels='Location_Easting_OSGR', axis=1, inplace=True)
train_set.drop(labels='Location_Northing_OSGR', axis=1, inplace=True)
print("Dopo -->", train_set.shape)
Prima --> (2037823, 50) Dopo --> (2037823, 47)
Vengono rimosse altre features che non sono utili ai fini del task come l'indice dell'incidente e del veicolo:
print("Prima -->", train_set.shape)
train_set.drop(labels='Accident_Index', axis=1, inplace=True)
train_set.drop(labels='Vehicle_Reference', axis=1, inplace=True)
train_set.drop(labels='Police_Force', axis=1, inplace=True)
train_set.drop(labels='1st_Road_Number', axis=1, inplace=True)
print("Dopo -->", train_set.shape)
Prima --> (2037823, 47) Dopo --> (2037823, 43)
Per quanto riguarda Age_of_Vehicle, EngineCapacity.CC., make e Propulsion_Code, non le si eliminano come features perchè potrebbero essere interessanti. Si crea una classe per un transformer che effettua la drop di colonne, che verrà inserito più avanti in una pipeline:
class ColumnDropperTransformer(BaseEstimator, TransformerMixin):
def __init__(self,columns):
self.columns=columns
def transform(self,X,y=None):
return X.drop(self.columns,axis=1)
def fit(self, X, y=None):
return self
#pipeline = Pipeline([
# ("columnDropper", ColumnDropperTransformer(['col_2','col_3']))
#])
Si eliminano tutte le righe che contengono almeno un valore null. Questa scelta è giustificata dall'enorme dataset che abbiamo a disposizione. Si crea una classe per un transformer che effettua la drop delle righe (passando come parametro l'indice delle righe da eliminare, se non definito verranno eliminate tutte le righe che contengono almeno un valore nullo), che verrà inserito più avanti in una pipeline:
class RowsDropperTransformer(BaseEstimator, TransformerMixin):
def __init__(self, indexNames=None):
self.indexNames = indexNames
def transform(self,X,y=None):
if self.indexNames is None:
return X.dropna()
if self.indexNames == 'Age_Band_of_Driver':
index = X[ (X[self.indexNames] == '0 - 5') | (X[self.indexNames] == '6 - 10') ].index
else:
index = X[ (X[self.indexNames] == 10.0) | (X[self.indexNames] == 15.0) ].index
return X.drop(index)
def fit(self, X, y=None):
return self
#pipeline = Pipeline([
# ("rowsDropper", RowsDropperTransformer())
#])
print("Prima -->", train_set.shape)
rowsNanDropper = RowsDropperTransformer()
train_set = rowsNanDropper.fit_transform(train_set)
print("Dopo -->", train_set.shape)
Prima --> (2037823, 43) Dopo --> (1418652, 43)
A questo punto non restano campi con valori nulli:
for i in train_set.isnull().sum():
if i!=0:
print("Sono presenti valori null!")
train_set.isnull().sum()
break
print("Non sono presenti valori null!")
Non sono presenti valori null!
In questa fase, invece si ricercano eventuali outliers nelle features numeriche, attraverso l'ausilio dei boxplot. In particolare, attualmente le colonne numeriche rimanenti sono le seguenti:
train_set.select_dtypes(["float", "int"]).columns
Index(['Age_of_Vehicle', 'Engine_Capacity_.CC.',
'Vehicle_Location.Restricted_Lane', 'Year',
'Did_Police_Officer_Attend_Scene_of_Accident', 'Latitude', 'Longitude',
'Number_of_Casualties', 'Number_of_Vehicles',
'Pedestrian_Crossing-Human_Control',
'Pedestrian_Crossing-Physical_Facilities', 'Speed_limit'],
dtype='object')
Di queste, le più importanti sono:
Le restanti saranno eliminate più avanti. Per qunato riguarda Latitude e Longitude, esse potrebbero presentare degli outliers corrspondenti agli incidenti avvenuti nell'isola Mainland, ovvero l'isola più a nord-est della Gran Bretagna, e quindi giustamente le coordinate degli incidenti si differenziano di molto dal resto delle coordinate. Però comunque si ritiene che tali valori non sono outliers perchè possono dare lo stesso un contributo nella fase di learning.
Quindi, le colonne che possono contenere degli outliers sono:
col_outliers = ['Age_of_Vehicle', 'Engine_Capacity_.CC.', 'Number_of_Casualties', 'Number_of_Vehicles', 'Speed_limit']
Si valuteranno i boxplot di ogniuna, suddivisi per gravità di incidente (Accident_Severity).
sns.boxplot(x = 'Accident_Severity', y = 'Age_of_Vehicle', data = train_set, palette='rocket')
<AxesSubplot:xlabel='Accident_Severity', ylabel='Age_of_Vehicle'>
sns.boxplot(x = 'Accident_Severity', y = 'Engine_Capacity_.CC.', data = train_set, palette='rocket')
<AxesSubplot:xlabel='Accident_Severity', ylabel='Engine_Capacity_.CC.'>
sns.boxplot(x = 'Accident_Severity', y = 'Number_of_Casualties', data = train_set, palette='rocket')
<AxesSubplot:xlabel='Accident_Severity', ylabel='Number_of_Casualties'>
sns.boxplot(x = 'Accident_Severity', y = 'Number_of_Vehicles', data = train_set, palette='rocket')
<AxesSubplot:xlabel='Accident_Severity', ylabel='Number_of_Vehicles'>
sns.boxplot(x = 'Accident_Severity', y = 'Speed_limit', data = train_set, palette='rocket')
<AxesSubplot:xlabel='Accident_Severity', ylabel='Speed_limit'>
Per il momento si considerano ouliers, tutti quei punti che superano 1.5 IQR. Sotto tale ipotesi, i risultati ottenuti mostrano che a parte la colonna Speed_limit, le altre contengono molti ouliers. A parte la colonna Age_of_Vehicle che contiene molti ouliers ma abbastanza comuni tra loro, le altre 3 colonne presentano dei veri e propri punti isolati. Basti vedere ad esempio la colonna Number_of_Vehicles* che contiene un incidente con circa 70 veicoli coinvolti, questo sicuramente è un outliers, dato che è un evento rarissimo (infatti solo un incidente del genere).
Per curiosità, su tale incidente si può andare a verificare cosa sia successo realmente quel giorno. Prendendo le coordinate dell'incidente e l'anno:
df = train_set[train_set['Number_of_Vehicles'] > 60].head(1)
lat, long, year = df.iloc[0]['Latitude'], df.iloc[0]['Longitude'], df.iloc[0]['Year']
lat, long, year
(51.39166, 0.749417, 2013)
In particolare le coordinate sopra menzionate corrispondono al ponte Sheppy Crossing a Sittingbourne in Inghilterra. Infatti nel 2013 su quel ponte c'è stato un enorme incidente di veicoli (pile-up), molto probabilmente dovuto anche all'alto livello di nebbia presente. Per maggiori informazioni ecco il link di Wikipedia che parla dello Sheppy Crossing crash: https://en.wikipedia.org/wiki/Sheppey_Crossing_crash
A questo punto si è deciso di rimuovere tutte le tuple che corrispondo a degli outliers, ovvero quei punti che superano di 1.5 * IQR. Si crea un transformer ad hoc, che verrà usato più avanti all'interno della pipeline:
class RowsDropperOutliersTransformer(BaseEstimator, TransformerMixin):
def __init__(self, indexNames=None, val_outliers=1.5):
self.indexNames = indexNames
self.val_outliers = val_outliers
def transform(self,X,y=None, remove_outliers=True):
if remove_outliers:
self.index_to_drop = self.__outlier_detection(X, self.indexNames)
X_clean = X.drop(self.index_to_drop)
else:
X_clean = X.copy()
return X_clean
def fit(self, X, y=None):
return self
def __outlier_detection(self, df, columns):
rows = []
to_drop_train = []
df_slight = df[df['Accident_Severity'] == 'Slight']
df_serious = df[df['Accident_Severity'] == 'Serious']
df_fatal = df[df['Accident_Severity'] == 'Fatal']
for col in columns:
for dfn in (df_slight, df_serious, df_fatal):
Q1 = np.nanpercentile(dfn[col], 25)
Q3 = np.nanpercentile(dfn[col], 75)
IQR = Q3 - Q1
outlier_point = self.val_outliers * IQR
rows.extend(dfn[(dfn[col] < Q1 - outlier_point)|(dfn[col] > Q3 + outlier_point)].index)
to_drop_train = np.unique(rows)
return to_drop_train
print("Prima -->", train_set.shape)
outlierTransformer = RowsDropperOutliersTransformer(col_outliers)
train_set = outlierTransformer.transform(train_set, remove_outliers=True)
print("Dopo -->", train_set.shape)
Prima --> (1418652, 43) Dopo --> (847994, 43)
Per verificare che gli outliers non sono più presenti basta andare a riplottare i boxplot. Essi saranno ripresentati nella sezione 4.2.2. Esplorazione attributi numerici in 4.2. Esplorazione delle features.
Un problema importante adesso da risolvere prima di proseguire è lo sbilanciamento della classe target; ci si trova in un problema di imbalanced learning:
def barPlotAccidentSeverity(label_pos_y=10000):
f = plt.figure(figsize=(15,7))
df_byAccSev = train_set.groupby("Accident_Severity", as_index=False).size()
df_byAccSev.columns = ["Accident_Severity", "Numero di incidenti"]
df_byAccSev.sort_values(by=["Numero di incidenti"], inplace=True, ascending=False)
plot = sns.barplot(x="Accident_Severity", y="Numero di incidenti", palette="rocket", data=df_byAccSev)
plot.get_yaxis().set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ',')))
plot.set_title("Numero di incidenti per gravità dell'incidente")
percentage = np.array(df_byAccSev[["Numero di incidenti"]]/train_set.shape[0] * 100)
patches = plot.patches
for i in range(len(patches)):
x = patches[i].get_x() + patches[i].get_width()/2
y = patches[i].get_height()+label_pos_y
plot.annotate('{:.1f}%'.format(float(percentage[i])), (x, y), ha='center', fontsize=14)
barPlotAccidentSeverity()
Come si vede l'80.4% delle istanze è di tipo Slight, il 17.7% di tipo Serious e peggio ancora davvero una piccolissima percentuale di tipo Fatal... L'idea innanzitutto è quella di trasformare il problema da un problema di classificazione multiclasse in un problema di classificazione binaria; verranno raggruppati in un'unica classe Serious e Fatal. Così facendo si andrà a diminuire di poco (1,9%) lo sbilanciamento. Dopo questa fase quindi il task sarà la classificazione di un problema binario, dove Accident_Severity sarà:
Si definisce una funzione per effettuare tale trasformazione:
def transformAccidentSverity(df):
df['Accident_Severity'] = df['Accident_Severity'].replace(['Serious', 'Fatal'], 'Serious or Fatal')
df = pd.get_dummies(df, columns=['Accident_Severity'])
df = df.drop('Accident_Severity_Slight', axis=1)
df['Accident_Severity_Serious or Fatal'].value_counts(normalize=True)
df = df.rename(columns={'Accident_Severity_Serious or Fatal': 'Accident_Severity'})
return df.drop('Accident_Severity', axis=1), df['Accident_Severity']
train_set, y = transformAccidentSverity(train_set)
train_set['Accident_Severity'] = y
Più avanti tale funzione verrà usata all'interno di un FunctionTransformer.
barPlotAccidentSeverity()
Nonostante il lieve miglioramento dello sbilanciamento, ancora c'è un forte sbilanciamento verso gli incidenti lievi (0). In questo caso anche un classificatore stupido che predice sempre il valore 0, otterrà un'accuratezza elevata dell'80,4%! Per risolvere tale problema, grazie al fatto che il dataset è costituito da molte istanze, si effettua un massiccio undersampling sulla classe maggioritaria (0). Con l'ausilio della libreria imbalanced-learn si procede con un undersampling random, in modo da avere un minor numero di tuple ma un bilanciamento perfetto delle classi. (Per maggiori informazioni sulla libreria imbalanced_learn si rimanda alla documentazione: https://imbalanced-learn.org/stable/index.html).
rus = RandomUnderSampler(random_state=0)
train_set, train_set['Accident_Severity'] = rus.fit_resample(train_set.loc[:, train_set.columns != 'Accident_Severity'], train_set['Accident_Severity'])
barPlotAccidentSeverity(label_pos_y=1000)
Definiamo una funzione che effettua l'undersampling in modo tale da poterla richiamare più avanti all'interno di un FunctionTransformer:
def underSampling(df):
df, y = df
rus = RandomUnderSampler(random_state=0)
df, y = rus.fit_resample(df.loc[:, df.columns != 'Accident_Severity'], y)
return df, y
Al costo di perdere istanze del dataset, grazie all'undersampling le classi sono perfettamente bilanciate, come si vede nel diagramma. Ecco di seguito il dataset finale:
print(train_set.shape)
train_set.head()
(332578, 43)
| Age_Band_of_Driver | Age_of_Vehicle | Driver_Home_Area_Type | Engine_Capacity_.CC. | Hit_Object_in_Carriageway | Hit_Object_off_Carriageway | Journey_Purpose_of_Driver | Junction_Location | make | Propulsion_Code | Sex_of_Driver | Skidding_and_Overturning | Towing_and_Articulation | Vehicle_Leaving_Carriageway | Vehicle_Location.Restricted_Lane | Vehicle_Manoeuvre | Vehicle_Type | Was_Vehicle_Left_Hand_Drive | X1st_Point_of_Impact | Year | 1st_Road_Class | Carriageway_Hazards | Day_of_Week | Did_Police_Officer_Attend_Scene_of_Accident | Junction_Detail | Latitude | Light_Conditions | Local_Authority_(District) | Local_Authority_(Highway) | Longitude | Number_of_Casualties | Number_of_Vehicles | Pedestrian_Crossing-Human_Control | Pedestrian_Crossing-Physical_Facilities | Road_Surface_Conditions | Road_Type | Special_Conditions_at_Site | Speed_limit | Time | Urban_or_Rural_Area | Weather_Conditions | InScotland | Accident_Severity | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 46 - 55 | 9.0 | Rural | 1598.0 | None | None | Journey as part of work | Entering roundabout | MINI | Petrol | Female | None | No tow/articulation | Did not leave carriageway | 0.0 | Turning right | Car | No | Did not impact | 2013 | A | None | Tuesday | 1.0 | Roundabout | 53.047616 | Daylight | Newcastle-under-Lyme | Staffordshire | -2.244131 | 1 | 2 | 0.0 | 0.0 | Wet or damp | Roundabout | None | 40.0 | 07:40 | Urban | Raining no high winds | No | 0 |
| 1 | 46 - 55 | 6.0 | Rural | 1998.0 | None | None | Not known | Approaching junction or waiting/parked at junc... | RENAULT | Petrol | Female | None | No tow/articulation | Did not leave carriageway | 0.0 | Turning right | Car | No | Nearside | 2011 | C | None | Wednesday | 2.0 | Private drive or entrance | 55.949146 | Daylight | Edinburgh, City of | Edinburgh, City of | -3.184619 | 1 | 2 | 0.0 | 0.0 | Dry | Single carriageway | None | 30.0 | 16:10 | Urban | Fine no high winds | Yes | 0 |
| 2 | 56 - 65 | 3.0 | Urban area | 2231.0 | None | None | Commuting to/from work | Mid Junction - on roundabout or on main road | TOYOTA | Heavy oil | Male | None | No tow/articulation | Did not leave carriageway | 0.0 | Turning right | Car | No | Front | 2011 | A | None | Wednesday | 1.0 | Crossroads | 53.762771 | Daylight | Preston | Lancashire | -2.740800 | 3 | 2 | 0.0 | 0.0 | Dry | Single carriageway | None | 30.0 | 08:25 | Urban | Fine no high winds | No | 0 |
| 3 | 46 - 55 | 7.0 | Urban area | 2188.0 | None | None | Commuting to/from work | Entering main road | RENAULT | Heavy oil | Male | None | No tow/articulation | Did not leave carriageway | 0.0 | Turning left | Car | No | Front | 2012 | A | None | Wednesday | 1.0 | Roundabout | 51.616884 | Daylight | Barnet | Barnet | -0.244740 | 2 | 2 | 0.0 | 8.0 | Wet or damp | Single carriageway | None | 30.0 | 06:55 | Urban | Unknown | No | 0 |
| 4 | 21 - 25 | 6.0 | Urban area | 1968.0 | None | None | Not known | Entering roundabout | VOLKSWAGEN | Heavy oil | Male | None | No tow/articulation | Did not leave carriageway | 0.0 | Going ahead other | Car | No | Offside | 2012 | A | None | Wednesday | 1.0 | Roundabout | 54.952193 | Darkness - lights lit | Gateshead | Gateshead | -1.554247 | 1 | 2 | 0.0 | 5.0 | Wet or damp | Roundabout | None | 30.0 | 22:45 | Urban | Fine no high winds | No | 0 |
Da questo momento in poi si porrà l'attenzione sul valore target da predire, ossia Accident_Severity, e sulla relazione che quest'ultimo ha con le altre features. Si procede alla visualizzazione dei dati per individuare i fattori che influenzano la classe target, ovvero la gravità dell'incidente. Così facendo si inizierà a capire l'utilità delle features in merito l'obiettivo del task.
Si definisce una funzione che servirà per plottare diagrammi a barre utili per visualizzare il legame di alcune features con Accident_Severity:
def plotBar(feature, x=10, y=5, vertical=False, percent=False, order=False):
f = plt.figure(figsize=(x,y))
df = train_set.groupby(feature, as_index=False).agg(
Accident_Severity=("Accident_Severity","mean"),
Number_of_Accidents=("Accident_Severity","size")
)
#df.columns = [feature, "Accident_Severity", "Number_of_Accidents"]
if not order:
df.sort_values(by=["Accident_Severity"], inplace=True, ascending=False)
col = "rocket"
else:
col = "rocket_r"
if percent:
percentage = np.array(df[["Number_of_Accidents"]]/train_set.shape[0] * 100)
if not vertical:
plot = sns.barplot(data=df, x=feature, y='Accident_Severity', palette=col, order=df[feature])
plot.get_yaxis().set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, p: '{:.2f}'.format(x, ',')))
if percent:
patches = plot.patches
for i in range(len(patches)):
x = patches[i].get_x() + patches[i].get_width()/2
y = patches[i].get_height()+0.001
plot.annotate('{:.1f}%'.format(float(percentage[i])), (x, y), ha='center', fontsize=14)
else:
plot = sns.barplot(data=df, x="Accident_Severity", y=feature, palette=col, order=df[feature])
plot.get_xaxis().set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, p: '{:.2f}'.format(x, ',')))
if percent:
patches = plot.patches
for i in range(len(patches)):
y = patches[i].get_y() + patches[i].get_height()/1.5
x = patches[i].get_width()+0.025
plot.annotate('{:.1f}%'.format(float(percentage[i])), (x, y), ha='center', fontsize=14)
Da questo punto si possono dividere le analisi delle features in relazione con la classe target, in 8 categorie: numeri, strada, tempo, posizione, condizioni incidente, condizioni veicolo, guidatore e veicolo. Queste analisi saranno distinte per tipo di attributi: categorici e numerici.
categorical = [var for var in train_set.columns if train_set[var].dtype=='O']
print('Ci sono {} attributi categorici\n'.format(len(categorical)))
print('Gli attributi categorici sono:\n\n', categorical)
Ci sono 30 attributi categorici Gli attributi categorici sono: ['Age_Band_of_Driver', 'Driver_Home_Area_Type', 'Hit_Object_in_Carriageway', 'Hit_Object_off_Carriageway', 'Journey_Purpose_of_Driver', 'Junction_Location', 'make', 'Propulsion_Code', 'Sex_of_Driver', 'Skidding_and_Overturning', 'Towing_and_Articulation', 'Vehicle_Leaving_Carriageway', 'Vehicle_Manoeuvre', 'Vehicle_Type', 'Was_Vehicle_Left_Hand_Drive', 'X1st_Point_of_Impact', '1st_Road_Class', 'Carriageway_Hazards', 'Day_of_Week', 'Junction_Detail', 'Light_Conditions', 'Local_Authority_(District)', 'Local_Authority_(Highway)', 'Road_Surface_Conditions', 'Road_Type', 'Special_Conditions_at_Site', 'Time', 'Urban_or_Rural_Area', 'Weather_Conditions', 'InScotland']
train_set[categorical].head()
| Age_Band_of_Driver | Driver_Home_Area_Type | Hit_Object_in_Carriageway | Hit_Object_off_Carriageway | Journey_Purpose_of_Driver | Junction_Location | make | Propulsion_Code | Sex_of_Driver | Skidding_and_Overturning | Towing_and_Articulation | Vehicle_Leaving_Carriageway | Vehicle_Manoeuvre | Vehicle_Type | Was_Vehicle_Left_Hand_Drive | X1st_Point_of_Impact | 1st_Road_Class | Carriageway_Hazards | Day_of_Week | Junction_Detail | Light_Conditions | Local_Authority_(District) | Local_Authority_(Highway) | Road_Surface_Conditions | Road_Type | Special_Conditions_at_Site | Time | Urban_or_Rural_Area | Weather_Conditions | InScotland | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 46 - 55 | Rural | None | None | Journey as part of work | Entering roundabout | MINI | Petrol | Female | None | No tow/articulation | Did not leave carriageway | Turning right | Car | No | Did not impact | A | None | Tuesday | Roundabout | Daylight | Newcastle-under-Lyme | Staffordshire | Wet or damp | Roundabout | None | 07:40 | Urban | Raining no high winds | No |
| 1 | 46 - 55 | Rural | None | None | Not known | Approaching junction or waiting/parked at junc... | RENAULT | Petrol | Female | None | No tow/articulation | Did not leave carriageway | Turning right | Car | No | Nearside | C | None | Wednesday | Private drive or entrance | Daylight | Edinburgh, City of | Edinburgh, City of | Dry | Single carriageway | None | 16:10 | Urban | Fine no high winds | Yes |
| 2 | 56 - 65 | Urban area | None | None | Commuting to/from work | Mid Junction - on roundabout or on main road | TOYOTA | Heavy oil | Male | None | No tow/articulation | Did not leave carriageway | Turning right | Car | No | Front | A | None | Wednesday | Crossroads | Daylight | Preston | Lancashire | Dry | Single carriageway | None | 08:25 | Urban | Fine no high winds | No |
| 3 | 46 - 55 | Urban area | None | None | Commuting to/from work | Entering main road | RENAULT | Heavy oil | Male | None | No tow/articulation | Did not leave carriageway | Turning left | Car | No | Front | A | None | Wednesday | Roundabout | Daylight | Barnet | Barnet | Wet or damp | Single carriageway | None | 06:55 | Urban | Unknown | No |
| 4 | 21 - 25 | Urban area | None | None | Not known | Entering roundabout | VOLKSWAGEN | Heavy oil | Male | None | No tow/articulation | Did not leave carriageway | Going ahead other | Car | No | Offside | A | None | Wednesday | Roundabout | Darkness - lights lit | Gateshead | Gateshead | Wet or damp | Roundabout | None | 22:45 | Urban | Fine no high winds | No |
plotBar("1st_Road_Class", percent=True)
Le strade più pericolose sono le tipo B, A, C, ecc. Le Motorway sono le più sicure anche se ci si aspettava il contrario essendo quelle in cui i veicoli hanno meno restrizioni di velocità.
Si definiscono alcune variabili utili nel proseguo:
colors = [
"#FF0000", "#00FF00", "#0000FF", "#FFFF00", "#FF00FF", "#00FFFF", "#000000",
"#800000", "#008000", "#000080", "#808000", "#800080", "#008080", "#808080",
"#C00000", "#00C000", "#0000C0", "#C0C000", "#C000C0", "#00C0C0", "#C0C0C0",
"#400000", "#004000", "#000040", "#404000", "#400040", "#004040", "#404040",
"#200000", "#002000", "#000020", "#202000", "#200020", "#002020", "#202020",
"#600000", "#006000", "#000060", "#606000", "#600060", "#006060", "#606060",
"#A00000", "#00A000", "#0000A0", "#A0A000", "#A000A0", "#00A0A0", "#A0A0A0",
"#E00000", "#00E000", "#0000E0", "#E0E000", "#E000E0", "#00E0E0", "#E0E0E0",
]
ac2005 = accidents.loc[accidents["Year"] == 2005]
a, b, c, d = ac2005.Longitude.min(), ac2005.Longitude.max(), ac2005.Latitude.min(), ac2005.Latitude.max()
mymap = plt.imread("./img/uk.png")
box = [a+0.1,b+0.1, c, d-0.05]
df_byR = pd.DataFrame(accidents['1st_Road_Class'].value_counts().sort_index()).reset_index()
df_byR.columns = ["1st_Road_Class", "Numero di incidenti"]
df_byR = df_byR.sort_values(ascending=False, by=["Numero di incidenti"])[0:20]
f = plt.figure(figsize=(8,12))
localAuth = df_byR["1st_Road_Class"].values
plt.imshow(mymap, alpha=1, zorder=0, extent=box)
plt.title("1st_Road_Class")
#for i in range(len(localAuth)):
i=0
acc_R = accidents.loc[accidents["1st_Road_Class"]=="Motorway"]
plt.scatter(
acc_R.Longitude, acc_R.Latitude,
alpha=0.5,
s=1,
label = "B",
c=colors[i]
)
plt.legend(markerscale=10)
plt.show()
In figura sono rappresentati tutti gli incidenti lungo le strade di tipo Motorway; come si vede sono le strade principali della nazione; e da quanto visto dall'analisi precedente sono più sicure delle altre.
plotBar("Road_Type", percent=True)
Le strade a singola carreggiata sono le più pericolose, andando verso le rotatoie che giustamente sono meno pericolose visto che i veicoli transitano molto più lenatemente nei loro pressi.
plotBar("Day_of_Week", percent=True)
Come prevedibile i giorni della settimana con incidenti più gravi sono quelli nel weekend.
Caratteristica interessante è la fascia oraria, infatti la maggior parte degli incidenti gravi avvengono di notte. Per tale ragione viene creato un nuovo campo (Time_Interval) a partire dal campo Time, grazie alla classe custom creata per il transformer:
class TimeTransformer(BaseEstimator, TransformerMixin):
def __init__(self):
pass
def transform(self,X,y=None):
X2 = X.copy()
X2['Time_Interval'] = pd.to_datetime(X2['Time'])
X2['Time_Interval'] = X2['Time_Interval'].dt.strftime('%H')
return X2.drop('Time', axis=1)
def fit(self, X, y=None):
return self
#pipeline = Pipeline([
# ("timeTransf", TimeTransformer())
#])
print("Prima -->", train_set.shape)
timeTransformer = TimeTransformer()
train_set = timeTransformer.fit_transform(train_set)
print("Dopo -->", train_set.shape)
Prima --> (332578, 43) Dopo --> (332578, 43)
plotBar("Time_Interval", percent=True, x=20, order=True)
Per avere una visione più chiara, viene mostrato un grafico a linea, in cui l'inizio sull'asse x sono le ore 08:00.
df = train_set.groupby('Time_Interval', as_index=False).agg(
Accident_Severity=("Accident_Severity","mean"),
Number_of_Accidents=("Accident_Severity","size")
)
df = df.reindex((df.index+8)%24)
plt.plot(df.Time_Interval, df.Accident_Severity, "-o")
plt.show()
Anche le ore della giornata giorno erano prevedibili, infatti gli incidenti più gravi avvengono durante la notte; come si vede dal grafico verso la notte la gravità degli incidenti aumenta. Il picco si trova alle 03:00 di notte.
f = plt.figure(figsize=(16,12))
ax = plt.subplot2grid((1, 2), (0,0))
df = train_set.groupby("Local_Authority_(District)", as_index=False).agg({"Latitude": np.mean, "Longitude": np.mean, "Accident_Severity": np.mean})
df.columns = ["Local_Authority_(District)","Latitude", "Longitude", "Accident_Severity"]
df.sort_values(by=["Accident_Severity"], inplace=True, ascending=False)
ax.imshow(mymap, alpha=1, zorder=0, extent=box)
plt.title("Local_Authority_(District)")
cm = plt.get_cmap("jet")
sc = ax.scatter(df["Longitude"], df["Latitude"], c=df["Accident_Severity"], vmin=0, vmax=1, s=35, cmap=cm)
plt.colorbar(sc,fraction=0.052)
ax2 = plt.subplot2grid((1, 2), (0,1))
df = train_set.groupby("Local_Authority_(Highway)", as_index=False).agg({"Latitude": np.mean, "Longitude": np.mean, "Accident_Severity": np.mean})
df.columns = ["Local_Authority_(Highway)","Latitude", "Longitude", "Accident_Severity"]
df.sort_values(by=["Accident_Severity"], inplace=True, ascending=False)
ax2.imshow(mymap, alpha=1, zorder=0, extent=box)
plt.title("Local_Authority_(Highway)")
cm = plt.get_cmap("jet")
sc = ax2.scatter(df["Longitude"], df["Latitude"], c=df["Accident_Severity"], vmin=0, vmax=1, s=35, cmap=cm)
plt.colorbar(sc,fraction=0.052)
plt.show()
In figura sono rappresentate le contee con la relativa gravità degli incidenti.
plotBar("Weather_Conditions", vertical=True, percent=True)
Le condizioni atmosferiche influiscono sulla pericolosità dell'incidente; infatti gli incidenti più gravi avvengono quando c'è nebbia e foschia.
plotBar("Light_Conditions", percent=True, x=12)
Le condizioni di luce anche sono molto importanti per stabilire la pericolosità di un incidente; infatti gli incidenti più pericolosi avvengono quando è presente poca luce (Darkness - no lighting).
plotBar("Road_Surface_Conditions", percent=True)
Le condizioni della strada pure sono importanti; gli incidenti più gravi avvengono in strade con allagamento con acqua alta sopra i 3 cm.
plotBar("Carriageway_Hazards", vertical=True, percent=True)
Anche i pericoli presenti sulla strada influiscono sulla gravità dell'incidente; come si vede laddove è presente già un incidente, si hanno incidenti più pericolosi.
plotBar("Special_Conditions_at_Site", vertical=True, percent=True)
Le condizioni speciali sono un altro attributo interessante, come si vede, si ha una maggiore pericolosità se la superficie stradale presenta dei difetti, seguita da una strada in cui è presente del liquido come benzina.
plotBar("Hit_Object_in_Carriageway", percent=True, vertical=True)
plotBar("Hit_Object_off_Carriageway", percent=True, vertical=True)
Altri attributi da poter tenere in considerazione sono gli oggetti colpiti in lungo la strada sia fuori che all'interno.
plotBar("Skidding_and_Overturning", percent=True, vertical=True)
plotBar("Vehicle_Leaving_Carriageway", percent=True, vertical=True)
plotBar("Vehicle_Manoeuvre", percent=True, vertical=True, y=8)
plotBar("Age_Band_of_Driver", percent=True)
L'intervallo di età del conducente, come si vede, è un attributo che determina molto la gravità dell'incidente; infatti dice che incidenti di bambini e anziani sono i più gravi. Da notare come ci sono due gruppi (0 - 5) e (6 - 10) che hanno un valore di gravità di incidente elevato, proprio pari ad 1! Solamente che nel training set rappresentano lo 0% circa delle istanze (outliers). Per capire meglio il numero di righe per queste due categorie:
train_set['Age_Band_of_Driver'].value_counts()
26 - 35 71591 36 - 45 68736 46 - 55 56279 21 - 25 40779 56 - 65 34204 16 - 20 29642 66 - 75 18323 Over 75 12917 11 - 15 99 6 - 10 6 0 - 5 2 Name: Age_Band_of_Driver, dtype: int64
Si nota come sono presenti pochissime righe, ovvero 3 righe per la fascia di età (6 - 10), e una sola riga per (0 - 5). Per tale motivo verrano eliminate queste due fasce d'età (la classe che effettua la trasformazione per il test set è stata definita già in precendenza e si chiama RowsDropperTransformer):
print("Prima -->", train_set.shape)
rowsAgeDriverDropper = RowsDropperTransformer('Age_Band_of_Driver')
train_set = rowsAgeDriverDropper.fit_transform(train_set)
print("Dopo -->", train_set.shape)
Prima --> (332578, 43) Dopo --> (332570, 43)
Ecco come appare il nuovo plotBar riguardo le fasce età del conducente:
plotBar("Age_Band_of_Driver", percent=True)
plotBar("Sex_of_Driver", percent=True)
Si nota come i guidatori maschi sono stati coinvolti o hanno causato incidenti più gravi delle donne.
plotBar("Vehicle_Type", percent=True, vertical=True, y=8)
Il tipo di veicolo può influire sulla gravità dell'incidente; esempio il taxi è più sicuro di una moto con più di 500 cavalli.
numerical = [var for var in train_set.columns if train_set[var].dtype!='O']
print('Ci sono {} attributi numerici\n'.format(len(numerical)))
print('Gli attributi numerici sono\n\n', numerical)
Ci sono 13 attributi numerici Gli attributi numerici sono ['Age_of_Vehicle', 'Engine_Capacity_.CC.', 'Vehicle_Location.Restricted_Lane', 'Year', 'Did_Police_Officer_Attend_Scene_of_Accident', 'Latitude', 'Longitude', 'Number_of_Casualties', 'Number_of_Vehicles', 'Pedestrian_Crossing-Human_Control', 'Pedestrian_Crossing-Physical_Facilities', 'Speed_limit', 'Accident_Severity']
sns.boxplot(x = 'Accident_Severity', y = 'Number_of_Casualties', data = train_set, palette='rocket')
<AxesSubplot:xlabel='Accident_Severity', ylabel='Number_of_Casualties'>
plotBar("Number_of_Casualties", order=True, x=15)
Un attributo importante è il numero di morti, infatti all'aumentare di quest'ultimo aumenta la gravità dell'incidente come si vede nel grafico. Stessa cosa si può dire per il numero di veicoli coinvolti:
sns.boxplot(x = 'Accident_Severity', y = 'Number_of_Vehicles', data = train_set, palette='rocket')
<AxesSubplot:xlabel='Accident_Severity', ylabel='Number_of_Vehicles'>
plotBar("Number_of_Vehicles", percent=True, x=15, order=True)
Si nota inoltre come nella maggior parte degli incidenti (78,7%) sono coinvolti 2 incidenti. Seguito dal 14,9% un solo veicolo, e così via all'aumentare del numero di veicoli la probabilità dell'evento diminuisce.
sns.boxplot(x = 'Accident_Severity', y = 'Speed_limit', data = train_set, palette='rocket')
<AxesSubplot:xlabel='Accident_Severity', ylabel='Speed_limit'>
plotBar("Speed_limit", percent=True, order=True)
Per quanto riguarda i limiti di velocità, come ci si aspettava, le strade con limiti di velocità più alti sono più pericolose. Da notare come ci sono i limiti di velocità 10 e 15 che hanno un valore di gravità di incidente elevato, proprio pari ad 1! Solamente che nel training set rappresentano lo 0% circa delle istanze (outliers). Per capire meglio il numero di righe per questi due limiti di velocità:
train_set['Speed_limit'].value_counts()
30.0 194141 60.0 64206 40.0 32305 70.0 22811 50.0 14342 20.0 4759 15.0 3 10.0 3 Name: Speed_limit, dtype: int64
Sono presenti pochissime righe, ovvero 3 righe per il limite di velocità 10, e 3 righe per 15. Per tale motivo verrano eliminate questi limiti (la classe che effettua la trasformazione per il test set è stata definita già in precendenza e si chiama RowsDropperTransformer):
print("Prima -->", train_set.shape)
rowsSpeedLimitDropper = RowsDropperTransformer('Speed_limit')
train_set = rowsSpeedLimitDropper.fit_transform(train_set)
print("Dopo -->", train_set.shape)
Prima --> (332570, 43) Dopo --> (332564, 43)
Ecco di seguito il nuovo diagramma a barre; si vede come adesso è più simile a come ci si aspettava, ovvero all'aumentare del limite di velocità, la gravità dell'incidente aumenta:
plotBar("Speed_limit", percent=True, order=True)
sns.boxplot(x = 'Accident_Severity', y = 'Year', data = train_set, palette='rocket')
<AxesSubplot:xlabel='Accident_Severity', ylabel='Year'>
plotBar("Year", percent=True, x=15, y=7, order=True)
L'anno in cui è avvenuto l'incidente può essere anche interessante, si nota un leggero incremento della gravità degli incidenti negli anni
sns.boxplot(x = 'Accident_Severity', y = 'Latitude', data = train_set, palette='rocket')
<AxesSubplot:xlabel='Accident_Severity', ylabel='Latitude'>
sns.boxplot(x = 'Accident_Severity', y = 'Longitude', data = train_set, palette='rocket')
<AxesSubplot:xlabel='Accident_Severity', ylabel='Longitude'>
f = plt.figure(figsize=(16,12))
plt.title("1st_Road_Class")
ax = plt.subplot2grid((1, 2), (0,0))
ax.imshow(mymap, alpha=1, zorder=0, extent=box)
acc_R = train_set.loc[train_set["Accident_Severity"]==1]
ax.scatter(
acc_R.Longitude, acc_R.Latitude,
alpha=0.5,
s=1,
label = "Severe",
c='red',
)
ax.legend(markerscale=10)
ax2 = plt.subplot2grid((1, 2), (0,1))
ax2.imshow(mymap, alpha=1, zorder=0, extent=box)
acc_R = train_set.loc[train_set["Accident_Severity"]==0]
ax2.scatter(
acc_R.Longitude, acc_R.Latitude,
alpha=0.5,
s=1,
label = "Slight",
c='green',
)
ax2.legend(markerscale=10)
plt.show()
A confronto sono le mappe degli incidenti Servere e Slight; in realtà non si notano ad occhio dei posti che sono più gravi di altri. Però tali pattern potrebbero essere scoperti da un classificatore, perciò le due features verranno lasciate nel dataset finale.
sns.boxplot(x = 'Accident_Severity', y = 'Age_of_Vehicle', data = train_set, palette='rocket')
<AxesSubplot:xlabel='Accident_Severity', ylabel='Age_of_Vehicle'>
plotBar("Age_of_Vehicle", percent=False, x=20, y=10, order=True)
Come si nota, l'attributo Age_of_Vehicle è importante perchè all'aumentare dell'età del veicolo aumenta la gravità dell'incidente. Nel dettaglio si nota come la gravità dell'incidente rimane costante per veicoli con età che va da 1 a 14 anni. Dai 15 anni in su aumenta la gravità dell'incidente.
sns.boxplot(x = 'Accident_Severity', y = 'Engine_Capacity_.CC.', data = train_set, palette='rocket')
<AxesSubplot:xlabel='Accident_Severity', ylabel='Engine_Capacity_.CC.'>
from sklearn.preprocessing import KBinsDiscretizer
est = KBinsDiscretizer(n_bins=50, encode='ordinal', strategy='uniform')
train_set['Engine_Capacity_.CC._Bin'] = est.fit_transform(train_set[['Engine_Capacity_.CC.']])
plotBar("Engine_Capacity_.CC._Bin", percent=False, x=30, y=10, order=True)
train_set.drop(labels='Engine_Capacity_.CC._Bin', axis=1, inplace=True)
Si nota anche come il numero di cavalli influisce sulla gravità dell'incidente. In figura sono stati raggrupati il numero di cavalli in 50 intervalli per una questione di visibilità. All'aumentare del numero di cavalli aumenta la gravità dell'incidente.
A questo punto arrivati, si effettua un'analisi della correlazione tra gli attributi numerici del training set:
fig,ax = plt.subplots(figsize=(20,10))
fig = sns.heatmap(train_set.corr(), annot=True)
plt.title("Dataset correlations", size=20)
plt.show()
Si nota una lieve correlazione positiva tra numero di morti e numero di veicoli coinvolti (pari a 0,21); è presente anche una correlazione negativa tra latitudine e longitudine (pari a -0,44), e tra Pedestrian_Crossing-Physical_Facilities e Speed_limit (pari a -0,21). Tali attributi potrebbero essere scartati e mantenuto solo uno per ciascuna coppia, ma per il momento verranno lasciati perchè più avanti nel caso verranno eliminati se il RandomForest non li riterrà features importanti. Per quanto riguarda invece l'attributo target (Accident_Severity) si nota che ha bassi valori di correlazione lineare con gli altri attributi numerici. Il valore più alto di correlazione è presente con l'attributo Did_Police_Offer_Attend_Scene_of_Accident (pari a -0.16). Però nessuno ci dice che è presente un qualche altra forma di correlazione che non sia lineare.
In questa sezione si eseguirà l'algoritmo del RandomForest sul training set per avere la lista ordinate degli attributi in ordine di importanza, e nel caso poter eliminare quelli che hanno un valore di importanza non rilevante. Per fare ciò verranno momentaneamente codificati gli attributi in label numeriche, in modo da rendere anche gli attributi categorici in formato numerico e quindi accettabile dall'algoritmo.
Encoder_df = LabelEncoder()
df = train_set.copy()
for c in df.columns:
df[c] = Encoder_df.fit_transform(df[c])
from sklearn.ensemble import RandomForestClassifier
filename = './models/rnd_clf_feature_importance_2.sav'
dfX = df.drop('Accident_Severity', axis = 1)
dfy = df['Accident_Severity']
# rnd_clf = RandomForestClassifier(n_estimators=40, n_jobs=-1, random_state=40)
# rnd_clf.fit(dfX, dfy)
# save the model to disk
# pickle.dump(rnd_clf, open(filename, 'wb'))
#load the model from disk
rnd_clf = pickle.load(open(filename, 'rb'))
attributes = dfX.columns
importances = rnd_clf.feature_importances_
index = np.argsort(importances)
plt.figure(figsize=(20,15))
plt.title("Attribute importance")
p = plt.barh(range(len(index)), importances[index], color='r', align='center')
plt.yticks(range(len(index)), attributes[index])
plt.xlabel("Relative importance")
plt.show()
Si nota come l'attributo più importante è Number_of_Vehicles seguito da EngineCapacity.CC. (cilindrata veicolo) e della posizione dell'incidente, in particolare latitudine e longitudine; segue anche il distretto di autorità locale. Anche l'orario in cui è avvenuto l'incidente, seguito dall'età del veicolo e dalla marca sono altrettanto importanti. Mentre si nota che l'attributo meno significativo è il Was_Vehicle_Left_Hand_Drive seguito da altri come InScotland e così via. Comunque si può affermare che molti di questi risulatati erano stati già ottenuti esplorando i singoli attributi in funzione dell'attributo target.
Dato che il numero di attributi è elevato, si rimuovono tutti gli attributi che sono meno importanti dell'attributo Weather_Conditions; ovvero rimarranno solamente 24 feature totali più quella target (25 features):
print("Prima -->", train_set.shape)
train_set.drop(labels='Was_Vehicle_Left_Hand_Drive', axis=1, inplace=True)
train_set.drop(labels='InScotland', axis=1, inplace=True)
train_set.drop(labels='Pedestrian_Crossing-Human_Control', axis=1, inplace=True)
train_set.drop(labels='Towing_and_Articulation', axis=1, inplace=True)
train_set.drop(labels='Vehicle_Location.Restricted_Lane', axis=1, inplace=True)
train_set.drop(labels='Carriageway_Hazards', axis=1, inplace=True)
train_set.drop(labels='Special_Conditions_at_Site', axis=1, inplace=True)
train_set.drop(labels='Sex_of_Driver', axis=1, inplace=True)
train_set.drop(labels='Skidding_and_Overturning', axis=1, inplace=True)
train_set.drop(labels='Hit_Object_off_Carriageway', axis=1, inplace=True)
train_set.drop(labels='Propulsion_Code', axis=1, inplace=True)
train_set.drop(labels='Road_Surface_Conditions', axis=1, inplace=True)
train_set.drop(labels='Light_Conditions', axis=1, inplace=True)
train_set.drop(labels='Driver_Home_Area_Type', axis=1, inplace=True)
train_set.drop(labels='Vehicle_Leaving_Carriageway', axis=1, inplace=True)
train_set.drop(labels='Pedestrian_Crossing-Physical_Facilities', axis=1, inplace=True)
train_set.drop(labels='Hit_Object_in_Carriageway', axis=1, inplace=True)
train_set.drop(labels='Urban_or_Rural_Area', axis=1, inplace=True)
print("Dopo -->", train_set.shape)
Prima --> (332564, 43) Dopo --> (332564, 25)
In questa fase, si preparano i dati da passare ai modelli di machine learning.
train_set_copy_2 = train_set.copy()
In questa parte verrà analizzata la dimensionalità degli attributi categorici, e laddove qualche attributi presenta un elevato numero di valori univoci, si attueranno delle tecniche di riduzione della dimensionalità.
categorical = [var for var in train_set.columns if train_set[var].dtype=='O']
plt.figure(figsize=(15,5))
s = pd.Series(train_set[categorical].nunique()).sort_values(ascending=False)
plot = sns.barplot(x = s.index, y = s.values)
plt.xticks(rotation=90)
plt.title("Dimensionalità attributi categorici", size=20)
patches = plot.patches
for i in range(len(patches)):
x = patches[i].get_x() + patches[i].get_width()/2
y = patches[i].get_height()+5
plot.annotate('{:.0f}'.format(float(s.values[i])), (x, y), ha='center', fontsize=14)
Come si vede, gli attributi con maggiore dimensionalità sono: LocalAuthority(District), make e LocalAuthority(Highway).
Iniziando ad analizzare LocalAuthority(District), quest'attributo presenta 416 valori univoci. Per ridurre la dimensionalità di tale attributi una possibile via è quella di raggruppare più local authority in base alla loro poszione giografica. Verrà adottata la tecnica di clustering Kmeans, e verrà scelto un numero di cluster pari a 20. Ecco di seguito il dataframe che rappresenta ogni distretto di autorità con rispettive coordinate geografiche (media delle cordinate geografiche presenti nel dataset relative a quel distretto di autorità) e con la gravità dell'incidente (media delle gravità degli incidenti presenti nel dataset relative a quel distretto di autorità):
df = train_set.groupby('Local_Authority_(District)', as_index=False).agg(
Latitude=("Latitude","mean"),
Longitude=("Longitude","mean"),
Accident_Severity=("Accident_Severity","mean")
)
df.sort_values(by=["Accident_Severity"], inplace=True, ascending=False)
df.head()
| Local_Authority_(District) | Latitude | Longitude | Accident_Severity | |
|---|---|---|---|---|
| 1 | Aberdeenshire | 57.287628 | -2.335154 | 0.787259 |
| 288 | Ryedale | 54.178870 | -0.837545 | 0.759931 |
| 264 | Powys | 52.326763 | -3.362590 | 0.742601 |
| 293 | Scottish Borders | 55.612100 | -2.745900 | 0.738095 |
| 277 | Richmondshire | 54.382432 | -1.788395 | 0.735537 |
X = df[['Longitude', 'Latitude']]
X
| Longitude | Latitude | |
|---|---|---|
| 1 | -2.335154 | 57.287628 |
| 288 | -0.837545 | 54.178870 |
| 264 | -3.362590 | 52.326763 |
| 293 | -2.745900 | 55.612100 |
| 277 | -1.788395 | 54.382432 |
| ... | ... | ... |
| 226 | -2.261118 | 53.023136 |
| 349 | -1.682462 | 52.624785 |
| 196 | -1.833053 | 52.677878 |
| 29 | -1.555640 | 55.096479 |
| 338 | -2.169440 | 53.016737 |
416 rows × 2 columns
A questo punto viene applicato il metodo Kmeans clustering su tale insieme di punti (coordinate dei distretti di autorità); e viene appesa una nuova colonna chiamata cluster, che indicherà il relativo cluster di appartenenza per lo specifico distretto di autorità:
X = df[['Longitude', 'Latitude']]
k = 20
kmeans = KMeans(n_clusters=k, random_state=42)
kmeans.fit(X)
df['cluster'] = kmeans.predict(X)
#df['cluster'] = df['cluster'].apply(str)
df
| Local_Authority_(District) | Latitude | Longitude | Accident_Severity | cluster | |
|---|---|---|---|---|---|
| 1 | Aberdeenshire | 57.287628 | -2.335154 | 0.787259 | 6 |
| 288 | Ryedale | 54.178870 | -0.837545 | 0.759931 | 7 |
| 264 | Powys | 52.326763 | -3.362590 | 0.742601 | 14 |
| 293 | Scottish Borders | 55.612100 | -2.745900 | 0.738095 | 15 |
| 277 | Richmondshire | 54.382432 | -1.788395 | 0.735537 | 7 |
| ... | ... | ... | ... | ... | ... |
| 226 | Newcastle-under-Lyme | 53.023136 | -2.261118 | 0.316558 | 9 |
| 349 | Tamworth | 52.624785 | -1.682462 | 0.297189 | 1 |
| 196 | Lichfield | 52.677878 | -1.833053 | 0.282486 | 1 |
| 29 | Blyth Valley | 55.096479 | -1.555640 | 0.275862 | 7 |
| 338 | Stoke-on-Trent | 53.016737 | -2.169440 | 0.251445 | 9 |
416 rows × 5 columns
I seguenti sono i centroidi dei cluster:
centers = pd.DataFrame(kmeans.cluster_centers_, columns=['Longitude','Latitude'])
centers
| Longitude | Latitude | |
|---|---|---|
| 0 | -4.383417 | 55.781044 |
| 1 | -2.107605 | 52.365486 |
| 2 | 0.597531 | 51.339690 |
| 3 | -3.021169 | 54.266435 |
| 4 | -4.428715 | 50.485996 |
| 5 | -1.058310 | 51.168564 |
| 6 | -3.030824 | 57.711439 |
| 7 | -1.522897 | 54.811662 |
| 8 | -0.979817 | 52.367081 |
| 9 | -2.543715 | 53.403071 |
| 10 | -2.181056 | 51.121147 |
| 11 | -4.222353 | 52.561097 |
| 12 | -1.388832 | 53.300638 |
| 13 | -0.211900 | 51.520149 |
| 14 | -3.294493 | 51.445339 |
| 15 | -3.229972 | 56.101788 |
| 16 | -0.295232 | 53.189273 |
| 17 | 1.040367 | 52.360163 |
| 18 | -6.706904 | 57.976669 |
| 19 | -1.234547 | 60.186866 |
Di seguito verrà mostrato il diagramma di Voronoi, in cui sono rappresentati i diversi centroidi sulla mappa geografica con i relativi distrtti di autorità e anche i confini di decisione:
def plot_data(X):
plt.plot(X[:, 0], X[:, 1], 'k.', markersize=5)
def plot_centroids(centroids, weights=None, circle_color='w', cross_color='blue'):
if weights is not None:
centroids = centroids[weights > weights.max() / 10]
plt.scatter(centroids[:, 0], centroids[:, 1],
marker='o', s=17, linewidths=10,
color=circle_color, zorder=10, alpha=0.9)
plt.scatter(centroids[:, 0], centroids[:, 1],
marker='x', s=15, linewidths=10,
color=cross_color, zorder=11, alpha=1)
def plot_decision_boundaries(clusterer, X, resolution=1000, show_centroids=True,
show_xlabels=True, show_ylabels=True):
mins = X.min(axis=0) - 0.1
maxs = X.max(axis=0) + 0.1
xx, yy = np.meshgrid(np.linspace(mins[0], maxs[0], resolution),
np.linspace(mins[1], maxs[1], resolution))
Z = clusterer.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.imshow(mymap, alpha=1, zorder=0, extent=box)
plt.contourf(Z, extent=(mins[0], maxs[0], mins[1], maxs[1]),
cmap="Pastel2", alpha=0.4)
plt.contour(Z, extent=(mins[0], maxs[0], mins[1], maxs[1]),
linewidths=1, colors='k')
plot_data(X)
if show_centroids:
plot_centroids(clusterer.cluster_centers_)
if show_xlabels:
plt.xlabel("$x_1$", fontsize=14)
else:
plt.tick_params(labelbottom=False)
if show_ylabels:
plt.ylabel("$x_2$", fontsize=14, rotation=0)
else:
plt.tick_params(labelleft=False)
plt.figure(figsize=(8, 10))
plot_decision_boundaries(kmeans, X.to_numpy())
plt.show()
Nella seguente figura sono riportati a sinistra i LocalAuthority(District), mentre a destra i rispettivi centroidi calcolati con l'algoritmo kmeans. Da notare i colori dei punti che rappresentano il valore di gravità dell'incidente:
f = plt.figure(figsize=(16,12))
ax = plt.subplot2grid((1, 2), (0,1))
df2 = df.groupby('cluster', as_index=False).agg(
Accident_Severity=("Accident_Severity","mean")
)
df2 = df2.join(centers)
ax.imshow(mymap, alpha=1, zorder=0, extent=box)
plt.title("Centroidi")
cm = plt.get_cmap("jet")
sc = ax.scatter(df2["Longitude"], df2["Latitude"], vmin=0, vmax=1, s=250, cmap=cm, c=df2["Accident_Severity"])
plt.colorbar(sc,fraction=0.052)
for index, row in df2.iterrows():
ax.annotate('{:.0f}'.format(row['cluster']), (row['Longitude']-0.03, row['Latitude']-0.1), ha='center', fontsize=12)
ax2 = plt.subplot2grid((1, 2), (0,0))
ax2.imshow(mymap, alpha=1, zorder=0, extent=box)
plt.title("Local_Authority_(District)")
cm = plt.get_cmap("jet")
sc = ax2.scatter(df["Longitude"], df["Latitude"], c=df["Accident_Severity"], vmin=0, vmax=1, s=35, cmap=cm)
plt.colorbar(sc,fraction=0.052)
plt.show()
A questo punto non resta che sostituire nel dataset i LocalAuthority(District) con i rispettivi centroidi così facendo, finalmente si ridurrà la dimensionalità di tale attributo da 416 valori univoci a ben soli 20 valori univoci. Per fare ciò si costruirà un dizionario in cui la chiave rappresenta il nome del distretto di autorità, mentre il valore è il rispettivo centroide a cui esso è associato. Per fare più veloce, di seguito viene crato un transformer che racchiude tutti questi passaggi (dal kmeans al replace), che servirà in seguito anche per modificare il test set:
class ClusteringReplaceValuesTransformer(BaseEstimator, TransformerMixin):
def __init__(self, feature, k=20):
self.feature=feature
self.k=k
def transform(self,X,y=None):
X2 = X.copy()
X2[self.feature].replace(self.dict, inplace=True)
return X2
def fit(self, X, y=None):
df = X.groupby(self.feature, as_index=False).agg(
Latitude=("Latitude","mean"),
Longitude=("Longitude","mean"),
Accident_Severity=("Accident_Severity","mean")
)
df.sort_values(by=["Accident_Severity"], inplace=True, ascending=False)
kmeans = KMeans(n_clusters=self.k, random_state=42)
kmeans.fit(df[['Longitude', 'Latitude']])
df['cluster'] = kmeans.predict(df[['Longitude', 'Latitude']])
df['cluster'] = df['cluster'].apply(str)
self.dict = df[[self.feature, 'cluster']].set_index(self.feature).to_dict()['cluster']
return self
#pipeline = Pipeline([
# ("replaceDistrict", ClusteringReplaceValuesTransformer("Local_Authority_(District)"))
clusteringReplaceDistrict = ClusteringReplaceValuesTransformer("Local_Authority_(District)")
train_set = clusteringReplaceDistrict.fit_transform(train_set)
train_set['Local_Authority_(District)'].value_counts()
13 67801 12 36588 9 36219 1 26995 5 22203 2 20068 8 16436 7 15458 10 15073 16 13178 17 11643 14 11257 0 10477 15 8939 4 6717 3 6525 6 4036 11 2836 18 59 19 56 Name: Local_Authority_(District), dtype: int64
L'operazione è stata eseguita con successo; come si può notare il centroide più frequente è il numero 13, non a caso se si vede sulla cartina sopra, si nota come il centroide 13 è nei pressi di Londra.
Per quanto riguarda l'attributo LocalAuthority(Highway), si possono rieseguire gli stessi ed identici passaggi effettuati per l'attributo LocalAuthority(District):
df = train_set.groupby('Local_Authority_(Highway)', as_index=False).agg(
Latitude=("Latitude","mean"),
Longitude=("Longitude","mean"),
Accident_Severity=("Accident_Severity","mean")
)
df.sort_values(by=["Accident_Severity"], inplace=True, ascending=False)
X = df[['Longitude', 'Latitude']]
k = 20
kmeans = KMeans(n_clusters=k, random_state=42)
kmeans.fit(X)
df['cluster'] = kmeans.predict(X)
centers = pd.DataFrame(kmeans.cluster_centers_, columns=['Longitude','Latitude'])
plt.figure(figsize=(8, 10))
plot_decision_boundaries(kmeans, X.to_numpy())
plt.show()
f = plt.figure(figsize=(16,12))
ax = plt.subplot2grid((1, 2), (0,1))
df2 = df.groupby('cluster', as_index=False).agg(
Accident_Severity=("Accident_Severity","mean")
)
df2 = df2.join(centers)
ax.imshow(mymap, alpha=1, zorder=0, extent=box)
plt.title("Centroidi")
cm = plt.get_cmap("jet")
sc = ax.scatter(df2["Longitude"], df2["Latitude"], vmin=0, vmax=1, s=250, cmap=cm, c=df2["Accident_Severity"])
plt.colorbar(sc,fraction=0.052)
for index, row in df2.iterrows():
ax.annotate('{:.0f}'.format(row['cluster']), (row['Longitude']-0.03, row['Latitude']-0.1), ha='center', fontsize=12)
ax2 = plt.subplot2grid((1, 2), (0,0))
ax2.imshow(mymap, alpha=1, zorder=0, extent=box)
plt.title("Local_Authority_(Highway)")
cm = plt.get_cmap("jet")
sc = ax2.scatter(df["Longitude"], df["Latitude"], c=df["Accident_Severity"], vmin=0, vmax=1, s=35, cmap=cm)
plt.colorbar(sc,fraction=0.052)
plt.show()
Per effettuare la replace dei valori si può usare lo stasso transformer creato in precedenza:
clusteringReplaceHighway = ClusteringReplaceValuesTransformer("Local_Authority_(Highway)")
train_set = clusteringReplaceHighway.fit_transform(train_set)
train_set['Local_Authority_(Highway)'].value_counts()
5 73034 11 38369 16 30938 15 29354 1 27557 7 27324 19 17234 9 13970 2 13937 0 13047 10 11183 3 11140 12 8276 13 8072 4 3915 6 2637 18 1399 8 1063 14 59 17 56 Name: Local_Authority_(Highway), dtype: int64
Ancora una volta possiamo vedere come il centroide più frequente si trova nei pressi di Londra.
Per quanto riguarda l'attributo make (marca del veicolo), si può vedere come molte marche di veicoli sono presenti in pochissimi incidenti. Per tale ragione si decide di scegliere una soglia del numero di incidenti (in questo caso si sceglierà 500 dopo avere fatto alcune prove), e di raggruppare tutte le marche di veicoli coinvolti in un numero di incidenti inferiore alla soglia in una nuova marca generale chiamata OTHERS. Così facendo si riduce di molto la dimensionalità dell'attributo make. Viene creato un transformer che effettua tale operazione, che sarà usato all'interno di una pipeline:
class VehiclesFeatureGroupNameTransformer(BaseEstimator, TransformerMixin):
def __init__(self, threshold=500, groupName='OTHERS', feature='make'):
self.threshold = threshold
self.groupName = groupName
self.feature = feature
def transform(self,X,y=None):
X2 = X.copy()
X2.loc[~X[self.feature].isin(self.makeNotToRemove), self.feature] = self.groupName
return X2
def fit(self, X, y=None):
self.makeNotToRemove = X.groupby(self.feature).filter(lambda x: len(x) >= self.threshold)[self.feature].unique()
return self
#pipeline = Pipeline([
# ("makeGroupOthers", vehiclesFeatureGroupNameTransformer())
#])
#train_set = VehiclesFeatureGroupNameTransformer().fit_transform(train_set)
numMake = len(train_set.groupby('make')['make'].unique())
makeToRemove = train_set.groupby('make').filter(lambda x: len(x) < 500)['make'].unique()
makeGroupNameOthers = VehiclesFeatureGroupNameTransformer()
train_set = makeGroupNameOthers.fit_transform(train_set)
print("Veranno raggruppate", len(makeToRemove), "marche su un totale di", numMake, "marche.")
print("Rimangono", numMake-len(makeToRemove)+1, "marche.")
Veranno raggruppate 251 marche su un totale di 296 marche. Rimangono 46 marche.
plotBar("make", percent=True, vertical=True, y=15)
Come prevedibile negli incidenti più gravi sono coinvolte maggiormente le moto, infatti le marche degli incidenti più gravi sono marche di motociclette, esempio: DUCATI, HARLEY-DAVIDSON, TRIUMPH, KAWASAKI, YAMAHA, APRILIA, SUZUKI, ecc. Ciò era prevedibile perchè le moto in caso di incidente sono molto meno sicure di un automobile.
In questa fase verranno convertiti tutti gli attributi categorici in numerici. Ecco di seguito la lista degli attributi categorici:
categorical = [var for var in train_set.columns if train_set[var].dtype=='O']
train_set[categorical].head()
| Age_Band_of_Driver | Journey_Purpose_of_Driver | Junction_Location | make | Vehicle_Manoeuvre | Vehicle_Type | X1st_Point_of_Impact | 1st_Road_Class | Day_of_Week | Junction_Detail | Local_Authority_(District) | Local_Authority_(Highway) | Road_Type | Weather_Conditions | Time_Interval | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 46 - 55 | Journey as part of work | Entering roundabout | MINI | Turning right | Car | Did not impact | A | Tuesday | Roundabout | 9 | 16 | Roundabout | Raining no high winds | 07 |
| 1 | 46 - 55 | Not known | Approaching junction or waiting/parked at junc... | RENAULT | Turning right | Car | Nearside | C | Wednesday | Private drive or entrance | 15 | 12 | Single carriageway | Fine no high winds | 16 |
| 2 | 56 - 65 | Commuting to/from work | Mid Junction - on roundabout or on main road | TOYOTA | Turning right | Car | Front | A | Wednesday | Crossroads | 9 | 7 | Single carriageway | Fine no high winds | 08 |
| 3 | 46 - 55 | Commuting to/from work | Entering main road | RENAULT | Turning left | Car | Front | A | Wednesday | Roundabout | 13 | 5 | Single carriageway | Unknown | 06 |
| 4 | 21 - 25 | Not known | Entering roundabout | VOLKSWAGEN | Going ahead other | Car | Offside | A | Wednesday | Roundabout | 7 | 0 | Roundabout | Fine no high winds | 22 |
Come si può vedere ed intuire, gli unici attributi che presentano un ordine sono: Age_Band_of_Driver, Time_Interval e Day_of_Week. Per questi tre attributi la soluzione sarà quella di adottare la classe OrdinalEncoder per l'attributo Age_Band_of_Driver, mentre per gli altri due attributi temporali, dato che è presente anche un ordine circolare perchè le ore e i giorni della settimana si ripetono nel tempo, la soluzione scelta è quella di tener conto di questa caratteristica convertendoli come "punti" su un cerchio, rappresentati da due nuove colonne ciascuno, rappresentante il seno e il coseno dell'angolo. Infine per i restanti attributi, essendo non ordinali, si può adottare tranquillamente la classe OneHotEncoder.
ordinal_encoder_AgeDriver = OrdinalEncoder()
train_set[['Age_Band_of_Driver']] = ordinal_encoder_AgeDriver.fit_transform(train_set[['Age_Band_of_Driver']])
train_set[['Age_Band_of_Driver']]
| Age_Band_of_Driver | |
|---|---|
| 0 | 5.0 |
| 1 | 5.0 |
| 2 | 6.0 |
| 3 | 5.0 |
| 4 | 2.0 |
| ... | ... |
| 332573 | 7.0 |
| 332574 | 3.0 |
| 332575 | 4.0 |
| 332576 | 4.0 |
| 332577 | 6.0 |
332564 rows × 1 columns
La trasformazione è stata eseguita, si vede di seguito le categorie come sono state ordinate:
ordinal_encoder_AgeDriver.categories_
[array(['11 - 15', '16 - 20', '21 - 25', '26 - 35', '36 - 45', '46 - 55',
'56 - 65', '66 - 75', 'Over 75'], dtype=object)]
Si nota come in automatico la classe OrdinalEncoder ha trovato il giusto ordinamento tra le categorie, infatti si nota un ordinamento crescente delle fasce di età nell'array.
Per i due attributi temporali (Day_of_Week e Time_Interval), il primo passaggio da compiere è trasformarli in numerici attraverso l'ausilio della classe OrdinalEncoder:
ordinal_encoder_DayWeek = OrdinalEncoder(categories=[['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']])
train_set[['Day_of_Week']] = ordinal_encoder_DayWeek.fit_transform(train_set[['Day_of_Week']])
train_set[['Day_of_Week']]
| Day_of_Week | |
|---|---|
| 0 | 1.0 |
| 1 | 2.0 |
| 2 | 2.0 |
| 3 | 2.0 |
| 4 | 2.0 |
| ... | ... |
| 332573 | 5.0 |
| 332574 | 3.0 |
| 332575 | 2.0 |
| 332576 | 6.0 |
| 332577 | 1.0 |
332564 rows × 1 columns
ordinal_encoder_DayWeek.categories_
[array(['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday',
'Sunday'], dtype=object)]
ordinal_encoder_TimeInterval = OrdinalEncoder()
train_set[['Time_Interval']] = ordinal_encoder_TimeInterval.fit_transform(train_set[['Time_Interval']])
train_set[['Time_Interval']]
| Time_Interval | |
|---|---|
| 0 | 7.0 |
| 1 | 16.0 |
| 2 | 8.0 |
| 3 | 6.0 |
| 4 | 22.0 |
| ... | ... |
| 332573 | 16.0 |
| 332574 | 13.0 |
| 332575 | 12.0 |
| 332576 | 13.0 |
| 332577 | 7.0 |
332564 rows × 1 columns
ordinal_encoder_TimeInterval.categories_
[array(['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10',
'11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21',
'22', '23'], dtype=object)]
Dopo aver controllato che la codifica è ordinata, si passa alla costruzione delle due nuove colonne ciascuna, che rappresentano il seno e coseno dei punti nell'angolo. Le formule sono le seguenti: Day_of_Week: $$ \sin{(\frac{d}{7}*2*\pi)} $$ $$ \cos{(\frac{d}{7}*2*\pi)} $$
Time_Interval:
$$ \sin{(\frac{t}{24}*2*\pi)} $$$$ \cos{(\frac{t}{24}*2*\pi)} $$print("Prima -->", train_set.shape)
train_set['Day_of_Week_sin'] = np.sin(train_set['Day_of_Week'] * (2 * np.pi / 7))
train_set['Day_of_Week_cos'] = np.cos(train_set['Day_of_Week'] * (2 * np.pi / 7))
train_set.drop(labels='Day_of_Week', axis=1, inplace=True)
print("Dopo -->", train_set.shape)
Prima --> (332564, 25) Dopo --> (332564, 26)
print("Prima -->", train_set.shape)
train_set['Time_Interval_sin'] = np.sin(train_set['Time_Interval'] * (2 * np.pi / 24))
train_set['Time_Interval_cos'] = np.cos(train_set['Time_Interval'] * (2 * np.pi / 24))
train_set.drop(labels='Time_Interval', axis=1, inplace=True)
print("Dopo -->", train_set.shape)
Prima --> (332564, 26) Dopo --> (332564, 27)
Viene crato un transformer che esegue tutta queste serie di trasformazioni per tali attributi:
class CircularEncoder(BaseEstimator, TransformerMixin):
def __init__(self, feature='Time_Interval', cat=None, number=24):
self.feature = feature
self.cat = cat
self.number = number
def transform(self,X,y=None):
if self.cat is None:
self.ordinal_encoder = OrdinalEncoder()
else:
self.ordinal_encoder = OrdinalEncoder(categories=self.cat)
self.ordinal_feature = self.ordinal_encoder.fit_transform(X[[self.feature]])
X2 = X.copy()
X2[self.feature+'_sin'] = np.sin(self.ordinal_feature * (2 * np.pi / self.number))
X2[self.feature+'_cos'] = np.cos(self.ordinal_feature * (2 * np.pi / self.number))
X2.drop(labels=self.feature, axis=1, inplace=True)
return X2
def fit(self, X, y=None):
return self
Per tutti i restanti attributi categorici come detto in precedenza è possibile adottare la classe OneHotEncoder:
print("Prima -->", train_set.shape)
categorical = [var for var in train_set.columns if train_set[var].dtype=='O']
cat_encoder = OneHotEncoder(sparse=False)
cat_encoder.fit(train_set[categorical])
def get_cat_encoder(df):
temp_df = pd.DataFrame(data=cat_encoder.transform(df[categorical]), columns=cat_encoder.get_feature_names_out())
df.drop(columns=categorical, axis=1, inplace=True)
df = pd.concat([df.reset_index(drop=True), temp_df], axis=1)
return df
train_set = get_cat_encoder(train_set)
print("Dopo -->", train_set.shape)
Prima --> (332564, 27) Dopo --> (332564, 186)
train_set.head()
| Age_Band_of_Driver | Age_of_Vehicle | Engine_Capacity_.CC. | Year | Did_Police_Officer_Attend_Scene_of_Accident | Latitude | Longitude | Number_of_Casualties | Number_of_Vehicles | Speed_limit | Accident_Severity | Day_of_Week_sin | Day_of_Week_cos | Time_Interval_sin | Time_Interval_cos | Journey_Purpose_of_Driver_Commuting to/from work | Journey_Purpose_of_Driver_Journey as part of work | Journey_Purpose_of_Driver_Not known | Journey_Purpose_of_Driver_Other | Journey_Purpose_of_Driver_Other/Not known (2005-10) | Journey_Purpose_of_Driver_Pupil riding to/from school | Journey_Purpose_of_Driver_Taking pupil to/from school | Junction_Location_Approaching junction or waiting/parked at junction approach | Junction_Location_Cleared junction or waiting/parked at junction exit | Junction_Location_Entering from slip road | Junction_Location_Entering main road | Junction_Location_Entering roundabout | Junction_Location_Leaving main road | Junction_Location_Leaving roundabout | Junction_Location_Mid Junction - on roundabout or on main road | Junction_Location_Not at or within 20 metres of junction | make_ALFA ROMEO | make_APRILIA | make_AUDI | make_BMW | make_CHEVROLET | make_CHRYSLER | make_CITROEN | make_DAEWOO | make_DAIHATSU | make_DUCATI | make_FIAT | make_FORD | make_HARLEY-DAVIDSON | make_HONDA | make_HYUNDAI | make_IVECO | make_JAGUAR | make_KAWASAKI | make_KIA | make_KTM | make_LAND ROVER | make_LEXUS | make_LONDON TAXIS INT | make_MAZDA | make_MERCEDES | make_MG | make_MINI | make_MITSUBISHI | make_NISSAN | make_OTHERS | make_PEUGEOT | make_PIAGGIO | make_RENAULT | make_ROVER | make_SAAB | make_SEAT | make_SKODA | make_SMART | make_SUBARU | make_SUZUKI | make_TOYOTA | make_TRIUMPH | make_VAUXHALL | make_VOLKSWAGEN | make_VOLVO | make_YAMAHA | Vehicle_Manoeuvre_Changing lane to left | Vehicle_Manoeuvre_Changing lane to right | Vehicle_Manoeuvre_Going ahead left-hand bend | Vehicle_Manoeuvre_Going ahead other | Vehicle_Manoeuvre_Going ahead right-hand bend | Vehicle_Manoeuvre_Moving off | Vehicle_Manoeuvre_Overtaking - nearside | Vehicle_Manoeuvre_Overtaking moving vehicle - offside | Vehicle_Manoeuvre_Overtaking static vehicle - offside | Vehicle_Manoeuvre_Parked | Vehicle_Manoeuvre_Reversing | Vehicle_Manoeuvre_Slowing or stopping | Vehicle_Manoeuvre_Turning left | Vehicle_Manoeuvre_Turning right | Vehicle_Manoeuvre_U-turn | Vehicle_Manoeuvre_Waiting to go - held up | Vehicle_Manoeuvre_Waiting to turn left | Vehicle_Manoeuvre_Waiting to turn right | Vehicle_Type_Agricultural vehicle | Vehicle_Type_Bus or coach (17 or more pass seats) | Vehicle_Type_Car | Vehicle_Type_Electric motorcycle | Vehicle_Type_Goods 7.5 tonnes mgw and over | Vehicle_Type_Goods over 3.5t. and under 7.5t | Vehicle_Type_Goods vehicle - unknown weight | Vehicle_Type_Minibus (8 - 16 passenger seats) | Vehicle_Type_Motorcycle - unknown cc | Vehicle_Type_Motorcycle 125cc and under | Vehicle_Type_Motorcycle 50cc and under | Vehicle_Type_Motorcycle over 125cc and up to 500cc | Vehicle_Type_Motorcycle over 500cc | Vehicle_Type_Other vehicle | Vehicle_Type_Taxi/Private hire car | Vehicle_Type_Van / Goods 3.5 tonnes mgw or under | X1st_Point_of_Impact_Back | X1st_Point_of_Impact_Did not impact | X1st_Point_of_Impact_Front | X1st_Point_of_Impact_Nearside | X1st_Point_of_Impact_Offside | 1st_Road_Class_A | 1st_Road_Class_A(M) | 1st_Road_Class_B | 1st_Road_Class_C | 1st_Road_Class_Motorway | 1st_Road_Class_Unclassified | Junction_Detail_Crossroads | Junction_Detail_Mini-roundabout | Junction_Detail_More than 4 arms (not roundabout) | Junction_Detail_Not at junction or within 20 metres | Junction_Detail_Other junction | Junction_Detail_Private drive or entrance | Junction_Detail_Roundabout | Junction_Detail_Slip road | Junction_Detail_T or staggered junction | Local_Authority_(District)_0 | Local_Authority_(District)_1 | Local_Authority_(District)_10 | Local_Authority_(District)_11 | Local_Authority_(District)_12 | Local_Authority_(District)_13 | Local_Authority_(District)_14 | Local_Authority_(District)_15 | Local_Authority_(District)_16 | Local_Authority_(District)_17 | Local_Authority_(District)_18 | Local_Authority_(District)_19 | Local_Authority_(District)_2 | Local_Authority_(District)_3 | Local_Authority_(District)_4 | Local_Authority_(District)_5 | Local_Authority_(District)_6 | Local_Authority_(District)_7 | Local_Authority_(District)_8 | Local_Authority_(District)_9 | Local_Authority_(Highway)_0 | Local_Authority_(Highway)_1 | Local_Authority_(Highway)_10 | Local_Authority_(Highway)_11 | Local_Authority_(Highway)_12 | Local_Authority_(Highway)_13 | Local_Authority_(Highway)_14 | Local_Authority_(Highway)_15 | Local_Authority_(Highway)_16 | Local_Authority_(Highway)_17 | Local_Authority_(Highway)_18 | Local_Authority_(Highway)_19 | Local_Authority_(Highway)_2 | Local_Authority_(Highway)_3 | Local_Authority_(Highway)_4 | Local_Authority_(Highway)_5 | Local_Authority_(Highway)_6 | Local_Authority_(Highway)_7 | Local_Authority_(Highway)_8 | Local_Authority_(Highway)_9 | Road_Type_Dual carriageway | Road_Type_One way street | Road_Type_Roundabout | Road_Type_Single carriageway | Road_Type_Slip road | Road_Type_Unknown | Weather_Conditions_Fine + high winds | Weather_Conditions_Fine no high winds | Weather_Conditions_Fog or mist | Weather_Conditions_Other | Weather_Conditions_Raining + high winds | Weather_Conditions_Raining no high winds | Weather_Conditions_Snowing + high winds | Weather_Conditions_Snowing no high winds | Weather_Conditions_Unknown | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 5.0 | 9.0 | 1598.0 | 2013 | 1.0 | 53.047616 | -2.244131 | 1 | 2 | 40.0 | 0 | 0.781831 | 0.623490 | 0.965926 | -2.588190e-01 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 |
| 1 | 5.0 | 6.0 | 1998.0 | 2011 | 2.0 | 55.949146 | -3.184619 | 1 | 2 | 30.0 | 0 | 0.974928 | -0.222521 | -0.866025 | -5.000000e-01 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 2 | 6.0 | 3.0 | 2231.0 | 2011 | 1.0 | 53.762771 | -2.740800 | 3 | 2 | 30.0 | 0 | 0.974928 | -0.222521 | 0.866025 | -5.000000e-01 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 3 | 5.0 | 7.0 | 2188.0 | 2012 | 1.0 | 51.616884 | -0.244740 | 2 | 2 | 30.0 | 0 | 0.974928 | -0.222521 | 1.000000 | 6.123234e-17 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
| 4 | 2.0 | 6.0 | 1968.0 | 2012 | 1.0 | 54.952193 | -1.554247 | 1 | 2 | 30.0 | 0 | 0.974928 | -0.222521 | -0.500000 | 8.660254e-01 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
In questa fase, l'obiettivo è quello di rendere i valori degli attributi sulla stessa scala, in modo tale da poter avere buone performance anche per algoritmi di machine learning che non siano alberi decisionali:
train_set.describe()
| Age_Band_of_Driver | Age_of_Vehicle | Engine_Capacity_.CC. | Year | Did_Police_Officer_Attend_Scene_of_Accident | Latitude | Longitude | Number_of_Casualties | Number_of_Vehicles | Speed_limit | Accident_Severity | Day_of_Week_sin | Day_of_Week_cos | Time_Interval_sin | Time_Interval_cos | Journey_Purpose_of_Driver_Commuting to/from work | Journey_Purpose_of_Driver_Journey as part of work | Journey_Purpose_of_Driver_Not known | Journey_Purpose_of_Driver_Other | Journey_Purpose_of_Driver_Other/Not known (2005-10) | Journey_Purpose_of_Driver_Pupil riding to/from school | Journey_Purpose_of_Driver_Taking pupil to/from school | Junction_Location_Approaching junction or waiting/parked at junction approach | Junction_Location_Cleared junction or waiting/parked at junction exit | Junction_Location_Entering from slip road | Junction_Location_Entering main road | Junction_Location_Entering roundabout | Junction_Location_Leaving main road | Junction_Location_Leaving roundabout | Junction_Location_Mid Junction - on roundabout or on main road | Junction_Location_Not at or within 20 metres of junction | make_ALFA ROMEO | make_APRILIA | make_AUDI | make_BMW | make_CHEVROLET | make_CHRYSLER | make_CITROEN | make_DAEWOO | make_DAIHATSU | make_DUCATI | make_FIAT | make_FORD | make_HARLEY-DAVIDSON | make_HONDA | make_HYUNDAI | make_IVECO | make_JAGUAR | make_KAWASAKI | make_KIA | make_KTM | make_LAND ROVER | make_LEXUS | make_LONDON TAXIS INT | make_MAZDA | make_MERCEDES | make_MG | make_MINI | make_MITSUBISHI | make_NISSAN | make_OTHERS | make_PEUGEOT | make_PIAGGIO | make_RENAULT | make_ROVER | make_SAAB | make_SEAT | make_SKODA | make_SMART | make_SUBARU | make_SUZUKI | make_TOYOTA | make_TRIUMPH | make_VAUXHALL | make_VOLKSWAGEN | make_VOLVO | make_YAMAHA | Vehicle_Manoeuvre_Changing lane to left | Vehicle_Manoeuvre_Changing lane to right | Vehicle_Manoeuvre_Going ahead left-hand bend | Vehicle_Manoeuvre_Going ahead other | Vehicle_Manoeuvre_Going ahead right-hand bend | Vehicle_Manoeuvre_Moving off | Vehicle_Manoeuvre_Overtaking - nearside | Vehicle_Manoeuvre_Overtaking moving vehicle - offside | Vehicle_Manoeuvre_Overtaking static vehicle - offside | Vehicle_Manoeuvre_Parked | Vehicle_Manoeuvre_Reversing | Vehicle_Manoeuvre_Slowing or stopping | Vehicle_Manoeuvre_Turning left | Vehicle_Manoeuvre_Turning right | Vehicle_Manoeuvre_U-turn | Vehicle_Manoeuvre_Waiting to go - held up | Vehicle_Manoeuvre_Waiting to turn left | Vehicle_Manoeuvre_Waiting to turn right | Vehicle_Type_Agricultural vehicle | Vehicle_Type_Bus or coach (17 or more pass seats) | Vehicle_Type_Car | Vehicle_Type_Electric motorcycle | Vehicle_Type_Goods 7.5 tonnes mgw and over | Vehicle_Type_Goods over 3.5t. and under 7.5t | Vehicle_Type_Goods vehicle - unknown weight | Vehicle_Type_Minibus (8 - 16 passenger seats) | Vehicle_Type_Motorcycle - unknown cc | Vehicle_Type_Motorcycle 125cc and under | Vehicle_Type_Motorcycle 50cc and under | Vehicle_Type_Motorcycle over 125cc and up to 500cc | Vehicle_Type_Motorcycle over 500cc | Vehicle_Type_Other vehicle | Vehicle_Type_Taxi/Private hire car | Vehicle_Type_Van / Goods 3.5 tonnes mgw or under | X1st_Point_of_Impact_Back | X1st_Point_of_Impact_Did not impact | X1st_Point_of_Impact_Front | X1st_Point_of_Impact_Nearside | X1st_Point_of_Impact_Offside | 1st_Road_Class_A | 1st_Road_Class_A(M) | 1st_Road_Class_B | 1st_Road_Class_C | 1st_Road_Class_Motorway | 1st_Road_Class_Unclassified | Junction_Detail_Crossroads | Junction_Detail_Mini-roundabout | Junction_Detail_More than 4 arms (not roundabout) | Junction_Detail_Not at junction or within 20 metres | Junction_Detail_Other junction | Junction_Detail_Private drive or entrance | Junction_Detail_Roundabout | Junction_Detail_Slip road | Junction_Detail_T or staggered junction | Local_Authority_(District)_0 | Local_Authority_(District)_1 | Local_Authority_(District)_10 | Local_Authority_(District)_11 | Local_Authority_(District)_12 | Local_Authority_(District)_13 | Local_Authority_(District)_14 | Local_Authority_(District)_15 | Local_Authority_(District)_16 | Local_Authority_(District)_17 | Local_Authority_(District)_18 | Local_Authority_(District)_19 | Local_Authority_(District)_2 | Local_Authority_(District)_3 | Local_Authority_(District)_4 | Local_Authority_(District)_5 | Local_Authority_(District)_6 | Local_Authority_(District)_7 | Local_Authority_(District)_8 | Local_Authority_(District)_9 | Local_Authority_(Highway)_0 | Local_Authority_(Highway)_1 | Local_Authority_(Highway)_10 | Local_Authority_(Highway)_11 | Local_Authority_(Highway)_12 | Local_Authority_(Highway)_13 | Local_Authority_(Highway)_14 | Local_Authority_(Highway)_15 | Local_Authority_(Highway)_16 | Local_Authority_(Highway)_17 | Local_Authority_(Highway)_18 | Local_Authority_(Highway)_19 | Local_Authority_(Highway)_2 | Local_Authority_(Highway)_3 | Local_Authority_(Highway)_4 | Local_Authority_(Highway)_5 | Local_Authority_(Highway)_6 | Local_Authority_(Highway)_7 | Local_Authority_(Highway)_8 | Local_Authority_(Highway)_9 | Road_Type_Dual carriageway | Road_Type_One way street | Road_Type_Roundabout | Road_Type_Single carriageway | Road_Type_Slip road | Road_Type_Unknown | Weather_Conditions_Fine + high winds | Weather_Conditions_Fine no high winds | Weather_Conditions_Fog or mist | Weather_Conditions_Other | Weather_Conditions_Raining + high winds | Weather_Conditions_Raining no high winds | Weather_Conditions_Snowing + high winds | Weather_Conditions_Snowing no high winds | Weather_Conditions_Unknown | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| count | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 3.325640e+05 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.00000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.00000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 | 332564.000000 |
| mean | 3.966491 | 7.179611 | 1564.904178 | 2011.368531 | 1.122097 | 52.611099 | -1.423594 | 1.374995 | 1.921173 | 40.226362 | 0.499994 | 0.030536 | -0.041387 | -0.245658 | -3.320294e-01 | 0.116212 | 0.132074 | 0.423518 | 0.020586 | 0.294689 | 0.001588 | 0.011333 | 0.214052 | 0.050547 | 0.00335 | 0.056642 | 0.030021 | 0.032511 | 0.014157 | 0.227222 | 0.371498 | 0.002733 | 0.004270 | 0.026548 | 0.036480 | 0.002715 | 0.001879 | 0.040407 | 0.003118 | 0.002090 | 0.002294 | 0.029137 | 0.119132 | 0.002881 | 0.061669 | 0.012070 | 0.002240 | 0.004062 | 0.014518 | 0.010392 | 0.001509 | 0.012220 | 0.002096 | 0.005184 | 0.012163 | 0.031955 | 0.003936 | 0.008934 | 0.008149 | 0.035323 | 0.020113 | 0.066240 | 0.004192 | 0.055839 | 0.017200 | 0.004601 | 0.012133 | 0.016024 | 0.001891 | 0.002769 | 0.032640 | 0.044265 | 0.006486 | 0.121968 | 0.061949 | 0.012085 | 0.019500 | 0.006970 | 0.007899 | 0.047110 | 0.462302 | 0.050926 | 0.040567 | 0.004658 | 0.026064 | 0.012677 | 0.022501 | 0.011117 | 0.056939 | 0.033200 | 0.132432 | 0.010963 | 0.050249 | 0.005818 | 0.017609 | 0.000108 | 0.000493 | 0.789445 | 0.000021 | 0.00028 | 0.001110 | 0.000123 | 0.001470 | 0.000216 | 0.026395 | 0.007980 | 0.014833 | 0.075910 | 0.001314 | 0.024885 | 0.055415 | 0.141332 | 0.036748 | 0.520904 | 0.138437 | 0.162579 | 0.479724 | 0.002610 | 0.137159 | 0.083340 | 0.032872 | 0.264295 | 0.106635 | 0.011538 | 0.011459 | 0.371147 | 0.025613 | 0.045393 | 0.088596 | 0.013564 | 0.326055 | 0.031504 | 0.081172 | 0.045324 | 0.008528 | 0.110018 | 0.203874 | 0.033849 | 0.026879 | 0.039625 | 0.035010 | 0.000177 | 0.000168 | 0.060343 | 0.019620 | 0.020198 | 0.066763 | 0.012136 | 0.046481 | 0.049422 | 0.108908 | 0.039232 | 0.082862 | 0.033627 | 0.115373 | 0.024885 | 0.024272 | 0.000177 | 0.088266 | 0.093029 | 0.000168 | 0.004207 | 0.051822 | 0.041908 | 0.033497 | 0.011772 | 0.219609 | 0.007929 | 0.082162 | 0.003196 | 0.042007 | 0.142718 | 0.014451 | 0.070374 | 0.758654 | 0.009896 | 0.003906 | 0.013321 | 0.817548 | 0.005220 | 0.018273 | 0.012891 | 0.112802 | 0.001055 | 0.005894 | 0.012996 |
| std | 1.791501 | 4.419928 | 569.858981 | 3.258793 | 0.330051 | 1.483040 | 1.380300 | 0.660196 | 0.480276 | 14.398632 | 0.500001 | 0.700107 | 0.712186 | 0.699621 | 5.830447e-01 | 0.320480 | 0.338572 | 0.494117 | 0.141992 | 0.455904 | 0.039814 | 0.105852 | 0.410164 | 0.219070 | 0.05778 | 0.231157 | 0.170646 | 0.177353 | 0.118137 | 0.419038 | 0.483206 | 0.052210 | 0.065205 | 0.160759 | 0.187482 | 0.052038 | 0.043311 | 0.196913 | 0.055754 | 0.045667 | 0.047844 | 0.168191 | 0.323944 | 0.053594 | 0.240554 | 0.109198 | 0.047277 | 0.063607 | 0.119611 | 0.101410 | 0.038823 | 0.109868 | 0.045732 | 0.071813 | 0.109614 | 0.175880 | 0.062615 | 0.094095 | 0.089902 | 0.184594 | 0.140389 | 0.248701 | 0.064607 | 0.229611 | 0.130015 | 0.067672 | 0.109480 | 0.125568 | 0.043449 | 0.052552 | 0.177694 | 0.205684 | 0.080274 | 0.327249 | 0.241063 | 0.109265 | 0.138274 | 0.083196 | 0.088526 | 0.211874 | 0.498578 | 0.219846 | 0.197284 | 0.068089 | 0.159326 | 0.111878 | 0.148306 | 0.104848 | 0.231727 | 0.179158 | 0.338960 | 0.104130 | 0.218459 | 0.076057 | 0.131524 | 0.010404 | 0.022201 | 0.407703 | 0.004588 | 0.01672 | 0.033292 | 0.011103 | 0.038318 | 0.014712 | 0.160307 | 0.088976 | 0.120885 | 0.264855 | 0.036226 | 0.155776 | 0.228789 | 0.348364 | 0.188142 | 0.499564 | 0.345358 | 0.368982 | 0.499589 | 0.051022 | 0.344015 | 0.276396 | 0.178301 | 0.440958 | 0.308649 | 0.106792 | 0.106434 | 0.483112 | 0.157978 | 0.208164 | 0.284161 | 0.115673 | 0.468768 | 0.174675 | 0.273100 | 0.208013 | 0.091951 | 0.312913 | 0.402877 | 0.180841 | 0.161730 | 0.195078 | 0.183805 | 0.013318 | 0.012975 | 0.238122 | 0.138692 | 0.140676 | 0.249612 | 0.109493 | 0.210525 | 0.216748 | 0.311525 | 0.194146 | 0.275674 | 0.180266 | 0.319472 | 0.155776 | 0.153893 | 0.013318 | 0.283681 | 0.290473 | 0.012975 | 0.064723 | 0.221667 | 0.200379 | 0.179931 | 0.107859 | 0.413982 | 0.088693 | 0.274611 | 0.056446 | 0.200605 | 0.349786 | 0.119342 | 0.255777 | 0.427900 | 0.098985 | 0.062376 | 0.114644 | 0.386217 | 0.072061 | 0.133938 | 0.112803 | 0.316352 | 0.032470 | 0.076543 | 0.113257 |
| min | 0.000000 | 1.000000 | 10.000000 | 2005.000000 | 1.000000 | 49.915618 | -7.516225 | 1.000000 | 1.000000 | 20.000000 | 0.000000 | -0.974928 | -0.900969 | -1.000000 | -1.000000e+00 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 25% | 3.000000 | 3.000000 | 1242.000000 | 2009.000000 | 1.000000 | 51.481299 | -2.322458 | 1.000000 | 2.000000 | 30.000000 | 0.000000 | -0.781831 | -0.900969 | -0.866025 | -8.660254e-01 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 1.000000 | 0.000000 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 1.000000 | 0.000000 | 0.000000 | 0.000000 | 1.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 50% | 4.000000 | 7.000000 | 1596.000000 | 2012.000000 | 1.000000 | 52.358795 | -1.404380 | 1.000000 | 2.000000 | 30.000000 | 0.000000 | 0.000000 | -0.222521 | -0.500000 | -5.000000e-01 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 1.000000 | 0.000000 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 1.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 1.000000 | 0.000000 | 0.000000 | 0.000000 | 1.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 75% | 5.000000 | 10.000000 | 1968.000000 | 2014.000000 | 1.000000 | 53.499203 | -0.261969 | 2.000000 | 2.000000 | 60.000000 | 1.000000 | 0.781831 | 0.623490 | 0.500000 | -1.836970e-16 | 0.000000 | 0.000000 | 1.000000 | 0.000000 | 1.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 1.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 1.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 1.000000 | 0.000000 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 1.000000 | 0.000000 | 0.000000 | 1.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 1.000000 | 0.000000 | 0.000000 | 0.000000 | 1.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 1.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 1.000000 | 0.000000 | 0.000000 | 0.000000 | 1.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| max | 8.000000 | 20.000000 | 3700.000000 | 2016.000000 | 3.000000 | 60.662043 | 1.758661 | 6.000000 | 6.000000 | 70.000000 | 1.000000 | 0.974928 | 1.000000 | 1.000000 | 1.000000e+00 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.00000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.00000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 |
Non resta che portare tutti gli attributi sulla stessa scala, basta vedere ad esempio i valori massimi o medi tra Age_Band_of_Driver e EngineCapacity.CC., in cui è presente una differenza sostanziale.
print("Prima -->", train_set.shape)
train_set_X = train_set.loc[:, train_set.columns != 'Accident_Severity']
scaler = StandardScaler()
scaled_features = scaler.fit_transform(train_set_X)
train_set_X, train_set_y = pd.DataFrame(scaled_features, index=train_set_X.index, columns=train_set_X.columns), train_set['Accident_Severity']
print("Dopo X_train -->", train_set_X.shape)
print("Dopo y_train -->", train_set_y.shape)
Prima --> (332564, 186) Dopo X_train --> (332564, 185) Dopo y_train --> (332564,)
train_set_X.describe()
| Age_Band_of_Driver | Age_of_Vehicle | Engine_Capacity_.CC. | Year | Did_Police_Officer_Attend_Scene_of_Accident | Latitude | Longitude | Number_of_Casualties | Number_of_Vehicles | Speed_limit | Day_of_Week_sin | Day_of_Week_cos | Time_Interval_sin | Time_Interval_cos | Journey_Purpose_of_Driver_Commuting to/from work | Journey_Purpose_of_Driver_Journey as part of work | Journey_Purpose_of_Driver_Not known | Journey_Purpose_of_Driver_Other | Journey_Purpose_of_Driver_Other/Not known (2005-10) | Journey_Purpose_of_Driver_Pupil riding to/from school | Journey_Purpose_of_Driver_Taking pupil to/from school | Junction_Location_Approaching junction or waiting/parked at junction approach | Junction_Location_Cleared junction or waiting/parked at junction exit | Junction_Location_Entering from slip road | Junction_Location_Entering main road | Junction_Location_Entering roundabout | Junction_Location_Leaving main road | Junction_Location_Leaving roundabout | Junction_Location_Mid Junction - on roundabout or on main road | Junction_Location_Not at or within 20 metres of junction | make_ALFA ROMEO | make_APRILIA | make_AUDI | make_BMW | make_CHEVROLET | make_CHRYSLER | make_CITROEN | make_DAEWOO | make_DAIHATSU | make_DUCATI | make_FIAT | make_FORD | make_HARLEY-DAVIDSON | make_HONDA | make_HYUNDAI | make_IVECO | make_JAGUAR | make_KAWASAKI | make_KIA | make_KTM | make_LAND ROVER | make_LEXUS | make_LONDON TAXIS INT | make_MAZDA | make_MERCEDES | make_MG | make_MINI | make_MITSUBISHI | make_NISSAN | make_OTHERS | make_PEUGEOT | make_PIAGGIO | make_RENAULT | make_ROVER | make_SAAB | make_SEAT | make_SKODA | make_SMART | make_SUBARU | make_SUZUKI | make_TOYOTA | make_TRIUMPH | make_VAUXHALL | make_VOLKSWAGEN | make_VOLVO | make_YAMAHA | Vehicle_Manoeuvre_Changing lane to left | Vehicle_Manoeuvre_Changing lane to right | Vehicle_Manoeuvre_Going ahead left-hand bend | Vehicle_Manoeuvre_Going ahead other | Vehicle_Manoeuvre_Going ahead right-hand bend | Vehicle_Manoeuvre_Moving off | Vehicle_Manoeuvre_Overtaking - nearside | Vehicle_Manoeuvre_Overtaking moving vehicle - offside | Vehicle_Manoeuvre_Overtaking static vehicle - offside | Vehicle_Manoeuvre_Parked | Vehicle_Manoeuvre_Reversing | Vehicle_Manoeuvre_Slowing or stopping | Vehicle_Manoeuvre_Turning left | Vehicle_Manoeuvre_Turning right | Vehicle_Manoeuvre_U-turn | Vehicle_Manoeuvre_Waiting to go - held up | Vehicle_Manoeuvre_Waiting to turn left | Vehicle_Manoeuvre_Waiting to turn right | Vehicle_Type_Agricultural vehicle | Vehicle_Type_Bus or coach (17 or more pass seats) | Vehicle_Type_Car | Vehicle_Type_Electric motorcycle | Vehicle_Type_Goods 7.5 tonnes mgw and over | Vehicle_Type_Goods over 3.5t. and under 7.5t | Vehicle_Type_Goods vehicle - unknown weight | Vehicle_Type_Minibus (8 - 16 passenger seats) | Vehicle_Type_Motorcycle - unknown cc | Vehicle_Type_Motorcycle 125cc and under | Vehicle_Type_Motorcycle 50cc and under | Vehicle_Type_Motorcycle over 125cc and up to 500cc | Vehicle_Type_Motorcycle over 500cc | Vehicle_Type_Other vehicle | Vehicle_Type_Taxi/Private hire car | Vehicle_Type_Van / Goods 3.5 tonnes mgw or under | X1st_Point_of_Impact_Back | X1st_Point_of_Impact_Did not impact | X1st_Point_of_Impact_Front | X1st_Point_of_Impact_Nearside | X1st_Point_of_Impact_Offside | 1st_Road_Class_A | 1st_Road_Class_A(M) | 1st_Road_Class_B | 1st_Road_Class_C | 1st_Road_Class_Motorway | 1st_Road_Class_Unclassified | Junction_Detail_Crossroads | Junction_Detail_Mini-roundabout | Junction_Detail_More than 4 arms (not roundabout) | Junction_Detail_Not at junction or within 20 metres | Junction_Detail_Other junction | Junction_Detail_Private drive or entrance | Junction_Detail_Roundabout | Junction_Detail_Slip road | Junction_Detail_T or staggered junction | Local_Authority_(District)_0 | Local_Authority_(District)_1 | Local_Authority_(District)_10 | Local_Authority_(District)_11 | Local_Authority_(District)_12 | Local_Authority_(District)_13 | Local_Authority_(District)_14 | Local_Authority_(District)_15 | Local_Authority_(District)_16 | Local_Authority_(District)_17 | Local_Authority_(District)_18 | Local_Authority_(District)_19 | Local_Authority_(District)_2 | Local_Authority_(District)_3 | Local_Authority_(District)_4 | Local_Authority_(District)_5 | Local_Authority_(District)_6 | Local_Authority_(District)_7 | Local_Authority_(District)_8 | Local_Authority_(District)_9 | Local_Authority_(Highway)_0 | Local_Authority_(Highway)_1 | Local_Authority_(Highway)_10 | Local_Authority_(Highway)_11 | Local_Authority_(Highway)_12 | Local_Authority_(Highway)_13 | Local_Authority_(Highway)_14 | Local_Authority_(Highway)_15 | Local_Authority_(Highway)_16 | Local_Authority_(Highway)_17 | Local_Authority_(Highway)_18 | Local_Authority_(Highway)_19 | Local_Authority_(Highway)_2 | Local_Authority_(Highway)_3 | Local_Authority_(Highway)_4 | Local_Authority_(Highway)_5 | Local_Authority_(Highway)_6 | Local_Authority_(Highway)_7 | Local_Authority_(Highway)_8 | Local_Authority_(Highway)_9 | Road_Type_Dual carriageway | Road_Type_One way street | Road_Type_Roundabout | Road_Type_Single carriageway | Road_Type_Slip road | Road_Type_Unknown | Weather_Conditions_Fine + high winds | Weather_Conditions_Fine no high winds | Weather_Conditions_Fog or mist | Weather_Conditions_Other | Weather_Conditions_Raining + high winds | Weather_Conditions_Raining no high winds | Weather_Conditions_Snowing + high winds | Weather_Conditions_Snowing no high winds | Weather_Conditions_Unknown | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| count | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 | 3.325640e+05 |
| mean | 4.623316e-15 | -5.664097e-15 | 1.435521e-14 | 1.518574e-14 | 5.199369e-13 | 2.669815e-15 | 6.154192e-17 | -1.924623e-13 | -4.517127e-13 | 5.172120e-14 | 3.546034e-14 | -2.092001e-14 | -2.292259e-14 | -3.240941e-14 | -1.176168e-14 | -8.860316e-15 | -5.428479e-15 | 2.480550e-14 | 1.367618e-15 | -6.335245e-16 | -1.341869e-15 | -1.127924e-13 | -9.902704e-16 | -1.725220e-14 | -8.641879e-14 | 2.555796e-13 | -8.238199e-15 | -4.229166e-14 | -1.853246e-13 | 2.352970e-14 | -4.650737e-15 | -1.730447e-14 | 1.538848e-14 | -2.137653e-14 | -8.054145e-15 | 3.279765e-15 | -6.527677e-14 | -1.191398e-14 | 3.051109e-15 | 3.442164e-15 | 3.142583e-14 | 6.189213e-14 | 1.182808e-13 | 1.215595e-13 | 1.494999e-14 | 6.369352e-15 | 5.406998e-17 | -2.280113e-13 | 7.849542e-15 | -4.554964e-14 | 8.023766e-15 | -1.187515e-14 | -1.330892e-14 | -6.683220e-15 | 4.892247e-14 | -1.935676e-15 | -3.214301e-14 | -1.482408e-15 | 1.381629e-14 | -1.264191e-13 | -4.966287e-14 | 1.979066e-13 | 3.355857e-14 | -2.856724e-14 | 1.703448e-14 | -1.233286e-14 | -1.815475e-14 | -3.177032e-14 | 1.621087e-14 | 2.327194e-13 | 7.158854e-14 | -9.896966e-14 | 3.634902e-14 | 7.167841e-14 | 2.683089e-16 | -1.420919e-13 | 4.874309e-15 | -2.334289e-14 | 1.355827e-13 | -1.346229e-13 | -2.957528e-13 | -2.806658e-14 | -1.451219e-14 | 1.455842e-13 | -1.143778e-13 | 2.619961e-15 | -2.233797e-14 | -2.156327e-13 | -9.224180e-14 | 6.185753e-14 | -4.212766e-15 | 1.159516e-13 | -1.081451e-13 | 6.009825e-14 | 2.279590e-14 | -2.600342e-15 | -1.559218e-13 | 7.229099e-15 | -6.328297e-15 | 5.678562e-15 | -2.805521e-15 | -2.848381e-15 | -1.747096e-14 | 5.120421e-13 | -6.473366e-14 | -2.813008e-13 | -3.062970e-13 | 1.146089e-14 | -1.779863e-14 | 7.188442e-15 | 5.935955e-13 | -8.565452e-14 | -2.381048e-13 | -4.067094e-14 | -5.063360e-15 | 2.091510e-14 | -2.782875e-15 | -6.720181e-15 | -5.724628e-15 | -4.443515e-14 | 5.969065e-14 | -7.047890e-14 | 1.198895e-13 | -1.309216e-14 | 3.094762e-13 | 2.167783e-14 | -3.023852e-15 | -1.420714e-13 | -1.744732e-14 | -5.492172e-15 | -3.267520e-14 | 4.239440e-14 | 3.207654e-14 | -5.285016e-14 | -1.625067e-16 | 9.476737e-15 | -2.635370e-14 | -5.692766e-14 | 1.565589e-14 | 7.298859e-14 | -1.512149e-14 | 3.806777e-15 | -1.249253e-14 | -4.679024e-14 | -1.637030e-14 | -6.762462e-14 | -4.263053e-14 | -3.566005e-16 | -1.482717e-14 | 2.863599e-14 | -2.755234e-14 | 1.070881e-13 | 2.254020e-14 | 6.046995e-15 | -2.596575e-14 | -3.556813e-15 | -1.512149e-14 | -2.875652e-14 | -3.972978e-14 | 3.806777e-15 | -6.982550e-14 | 8.155019e-15 | 5.252823e-15 | -2.544325e-14 | -1.162649e-14 | 5.792304e-14 | -1.103862e-13 | 3.671653e-15 | 2.010435e-14 | -1.200381e-14 | 5.689792e-14 | -6.244151e-15 | 3.517882e-14 | 8.531897e-14 | -5.565734e-14 | -5.307353e-14 | 1.749337e-14 | 6.092677e-14 | -1.903435e-14 | -6.428460e-15 | -7.881757e-15 | -5.723709e-14 | -6.332313e-15 | -4.825001e-14 | 5.937877e-14 |
| std | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 | 1.000002e+00 |
| min | -2.214064e+00 | -1.398127e+00 | -2.728581e+00 | -1.954264e+00 | -3.699339e-01 | -1.817541e+00 | -4.413996e+00 | -5.680075e-01 | -1.918012e+00 | -1.404744e+00 | -1.436160e+00 | -1.206965e+00 | -1.078216e+00 | -1.145661e+00 | -3.626201e-01 | -3.900919e-01 | -8.571237e-01 | -1.449765e-01 | -6.463858e-01 | -3.987717e-02 | -1.070657e-01 | -5.218705e-01 | -2.307328e-01 | -5.797404e-02 | -2.450360e-01 | -1.759274e-01 | -1.833126e-01 | -1.198331e-01 | -5.422485e-01 | -7.688211e-01 | -5.235265e-02 | -6.548408e-02 | -1.651433e-01 | -1.945800e-01 | -5.217911e-02 | -4.339212e-02 | -2.052042e-01 | -5.592808e-02 | -4.576243e-02 | -4.795384e-02 | -1.732389e-01 | -3.677551e-01 | -5.374915e-02 | -2.563638e-01 | -1.105320e-01 | -4.738354e-02 | -6.386663e-02 | -1.213729e-01 | -1.024749e-01 | -3.888143e-02 | -1.112267e-01 | -4.582836e-02 | -7.218710e-02 | -1.109632e-01 | -1.816853e-01 | -6.286206e-02 | -9.494287e-02 | -9.064081e-02 | -1.913528e-01 | -1.432699e-01 | -2.663435e-01 | -6.487926e-02 | -2.431898e-01 | -1.322902e-01 | -6.798442e-02 | -1.108243e-01 | -1.276124e-01 | -4.353102e-02 | -5.269803e-02 | -1.836891e-01 | -2.152099e-01 | -8.079797e-02 | -3.727063e-01 | -2.569827e-01 | -1.106016e-01 | -1.410242e-01 | -8.377953e-02 | -8.923075e-02 | -2.223483e-01 | -9.272432e-01 | -2.316422e-01 | -2.056255e-01 | -6.840721e-02 | -1.635900e-01 | -1.133139e-01 | -1.517197e-01 | -1.060265e-01 | -2.457179e-01 | -1.853097e-01 | -3.907006e-01 | -1.052845e-01 | -2.300164e-01 | -7.650151e-02 | -1.338815e-01 | -1.040488e-02 | -2.221219e-02 | -1.936325e+00 | -4.587921e-03 | -1.672494e-02 | -3.332857e-02 | -1.110404e-02 | -3.837394e-02 | -1.471552e-02 | -1.646527e-01 | -8.969180e-02 | -1.227052e-01 | -2.866111e-01 | -3.627343e-02 | -1.597514e-01 | -2.422104e-01 | -4.057028e-01 | -1.953196e-01 | -1.042720e+00 | -4.008498e-01 | -4.406164e-01 | -9.602383e-01 | -5.115520e-02 | -3.986998e-01 | -3.015252e-01 | -1.843615e-01 | -5.993667e-01 | -3.454902e-01 | -1.080384e-01 | -1.076675e-01 | -7.682420e-01 | -1.621308e-01 | -2.180625e-01 | -3.117833e-01 | -1.172639e-01 | -6.955570e-01 | -1.803565e-01 | -2.972262e-01 | -2.178884e-01 | -9.274173e-02 | -3.515937e-01 | -5.060453e-01 | -1.871765e-01 | -1.661971e-01 | -2.031266e-01 | -1.904730e-01 | -1.332070e-02 | -1.297756e-02 | -2.534135e-01 | -1.414671e-01 | -1.435757e-01 | -2.674683e-01 | -1.108382e-01 | -2.207875e-01 | -2.280167e-01 | -3.495984e-01 | -2.020730e-01 | -3.005807e-01 | -1.865388e-01 | -3.611375e-01 | -1.597514e-01 | -1.577207e-01 | -1.332070e-02 | -3.111443e-01 | -3.202667e-01 | -1.297756e-02 | -6.499600e-02 | -2.337816e-01 | -2.091430e-01 | -1.861673e-01 | -1.091440e-01 | -5.304797e-01 | -8.940177e-02 | -2.991930e-01 | -5.662709e-02 | -2.094013e-01 | -4.080170e-01 | -1.210919e-01 | -2.751398e-01 | -1.772972e+00 | -9.997373e-02 | -6.262054e-02 | -1.161920e-01 | -2.116811e+00 | -7.243921e-02 | -1.364306e-01 | -1.142764e-01 | -3.565733e-01 | -3.250463e-02 | -7.699703e-02 | -1.147480e-01 |
| 25% | -5.394874e-01 | -9.456300e-01 | -5.666396e-01 | -7.268134e-01 | -3.699339e-01 | -7.618153e-01 | -6.512098e-01 | -5.680075e-01 | 1.641288e-01 | -7.102326e-01 | -1.160349e+00 | -1.206965e+00 | -8.867203e-01 | -9.158763e-01 | -3.626201e-01 | -3.900919e-01 | -8.571237e-01 | -1.449765e-01 | -6.463858e-01 | -3.987717e-02 | -1.070657e-01 | -5.218705e-01 | -2.307328e-01 | -5.797404e-02 | -2.450360e-01 | -1.759274e-01 | -1.833126e-01 | -1.198331e-01 | -5.422485e-01 | -7.688211e-01 | -5.235265e-02 | -6.548408e-02 | -1.651433e-01 | -1.945800e-01 | -5.217911e-02 | -4.339212e-02 | -2.052042e-01 | -5.592808e-02 | -4.576243e-02 | -4.795384e-02 | -1.732389e-01 | -3.677551e-01 | -5.374915e-02 | -2.563638e-01 | -1.105320e-01 | -4.738354e-02 | -6.386663e-02 | -1.213729e-01 | -1.024749e-01 | -3.888143e-02 | -1.112267e-01 | -4.582836e-02 | -7.218710e-02 | -1.109632e-01 | -1.816853e-01 | -6.286206e-02 | -9.494287e-02 | -9.064081e-02 | -1.913528e-01 | -1.432699e-01 | -2.663435e-01 | -6.487926e-02 | -2.431898e-01 | -1.322902e-01 | -6.798442e-02 | -1.108243e-01 | -1.276124e-01 | -4.353102e-02 | -5.269803e-02 | -1.836891e-01 | -2.152099e-01 | -8.079797e-02 | -3.727063e-01 | -2.569827e-01 | -1.106016e-01 | -1.410242e-01 | -8.377953e-02 | -8.923075e-02 | -2.223483e-01 | -9.272432e-01 | -2.316422e-01 | -2.056255e-01 | -6.840721e-02 | -1.635900e-01 | -1.133139e-01 | -1.517197e-01 | -1.060265e-01 | -2.457179e-01 | -1.853097e-01 | -3.907006e-01 | -1.052845e-01 | -2.300164e-01 | -7.650151e-02 | -1.338815e-01 | -1.040488e-02 | -2.221219e-02 | 5.164423e-01 | -4.587921e-03 | -1.672494e-02 | -3.332857e-02 | -1.110404e-02 | -3.837394e-02 | -1.471552e-02 | -1.646527e-01 | -8.969180e-02 | -1.227052e-01 | -2.866111e-01 | -3.627343e-02 | -1.597514e-01 | -2.422104e-01 | -4.057028e-01 | -1.953196e-01 | -1.042720e+00 | -4.008498e-01 | -4.406164e-01 | -9.602383e-01 | -5.115520e-02 | -3.986998e-01 | -3.015252e-01 | -1.843615e-01 | -5.993667e-01 | -3.454902e-01 | -1.080384e-01 | -1.076675e-01 | -7.682420e-01 | -1.621308e-01 | -2.180625e-01 | -3.117833e-01 | -1.172639e-01 | -6.955570e-01 | -1.803565e-01 | -2.972262e-01 | -2.178884e-01 | -9.274173e-02 | -3.515937e-01 | -5.060453e-01 | -1.871765e-01 | -1.661971e-01 | -2.031266e-01 | -1.904730e-01 | -1.332070e-02 | -1.297756e-02 | -2.534135e-01 | -1.414671e-01 | -1.435757e-01 | -2.674683e-01 | -1.108382e-01 | -2.207875e-01 | -2.280167e-01 | -3.495984e-01 | -2.020730e-01 | -3.005807e-01 | -1.865388e-01 | -3.611375e-01 | -1.597514e-01 | -1.577207e-01 | -1.332070e-02 | -3.111443e-01 | -3.202667e-01 | -1.297756e-02 | -6.499600e-02 | -2.337816e-01 | -2.091430e-01 | -1.861673e-01 | -1.091440e-01 | -5.304797e-01 | -8.940177e-02 | -2.991930e-01 | -5.662709e-02 | -2.094013e-01 | -4.080170e-01 | -1.210919e-01 | -2.751398e-01 | 5.640248e-01 | -9.997373e-02 | -6.262054e-02 | -1.161920e-01 | 4.724086e-01 | -7.243921e-02 | -1.364306e-01 | -1.142764e-01 | -3.565733e-01 | -3.250463e-02 | -7.699703e-02 | -1.147480e-01 |
| 50% | 1.870465e-02 | -4.063659e-02 | 5.456766e-02 | 1.937743e-01 | -3.699339e-01 | -1.701269e-01 | 1.392038e-02 | -5.680075e-01 | 1.641288e-01 | -7.102326e-01 | -4.361580e-02 | -2.543356e-01 | -3.635431e-01 | -2.880926e-01 | -3.626201e-01 | -3.900919e-01 | -8.571237e-01 | -1.449765e-01 | -6.463858e-01 | -3.987717e-02 | -1.070657e-01 | -5.218705e-01 | -2.307328e-01 | -5.797404e-02 | -2.450360e-01 | -1.759274e-01 | -1.833126e-01 | -1.198331e-01 | -5.422485e-01 | -7.688211e-01 | -5.235265e-02 | -6.548408e-02 | -1.651433e-01 | -1.945800e-01 | -5.217911e-02 | -4.339212e-02 | -2.052042e-01 | -5.592808e-02 | -4.576243e-02 | -4.795384e-02 | -1.732389e-01 | -3.677551e-01 | -5.374915e-02 | -2.563638e-01 | -1.105320e-01 | -4.738354e-02 | -6.386663e-02 | -1.213729e-01 | -1.024749e-01 | -3.888143e-02 | -1.112267e-01 | -4.582836e-02 | -7.218710e-02 | -1.109632e-01 | -1.816853e-01 | -6.286206e-02 | -9.494287e-02 | -9.064081e-02 | -1.913528e-01 | -1.432699e-01 | -2.663435e-01 | -6.487926e-02 | -2.431898e-01 | -1.322902e-01 | -6.798442e-02 | -1.108243e-01 | -1.276124e-01 | -4.353102e-02 | -5.269803e-02 | -1.836891e-01 | -2.152099e-01 | -8.079797e-02 | -3.727063e-01 | -2.569827e-01 | -1.106016e-01 | -1.410242e-01 | -8.377953e-02 | -8.923075e-02 | -2.223483e-01 | -9.272432e-01 | -2.316422e-01 | -2.056255e-01 | -6.840721e-02 | -1.635900e-01 | -1.133139e-01 | -1.517197e-01 | -1.060265e-01 | -2.457179e-01 | -1.853097e-01 | -3.907006e-01 | -1.052845e-01 | -2.300164e-01 | -7.650151e-02 | -1.338815e-01 | -1.040488e-02 | -2.221219e-02 | 5.164423e-01 | -4.587921e-03 | -1.672494e-02 | -3.332857e-02 | -1.110404e-02 | -3.837394e-02 | -1.471552e-02 | -1.646527e-01 | -8.969180e-02 | -1.227052e-01 | -2.866111e-01 | -3.627343e-02 | -1.597514e-01 | -2.422104e-01 | -4.057028e-01 | -1.953196e-01 | 9.590300e-01 | -4.008498e-01 | -4.406164e-01 | -9.602383e-01 | -5.115520e-02 | -3.986998e-01 | -3.015252e-01 | -1.843615e-01 | -5.993667e-01 | -3.454902e-01 | -1.080384e-01 | -1.076675e-01 | -7.682420e-01 | -1.621308e-01 | -2.180625e-01 | -3.117833e-01 | -1.172639e-01 | -6.955570e-01 | -1.803565e-01 | -2.972262e-01 | -2.178884e-01 | -9.274173e-02 | -3.515937e-01 | -5.060453e-01 | -1.871765e-01 | -1.661971e-01 | -2.031266e-01 | -1.904730e-01 | -1.332070e-02 | -1.297756e-02 | -2.534135e-01 | -1.414671e-01 | -1.435757e-01 | -2.674683e-01 | -1.108382e-01 | -2.207875e-01 | -2.280167e-01 | -3.495984e-01 | -2.020730e-01 | -3.005807e-01 | -1.865388e-01 | -3.611375e-01 | -1.597514e-01 | -1.577207e-01 | -1.332070e-02 | -3.111443e-01 | -3.202667e-01 | -1.297756e-02 | -6.499600e-02 | -2.337816e-01 | -2.091430e-01 | -1.861673e-01 | -1.091440e-01 | -5.304797e-01 | -8.940177e-02 | -2.991930e-01 | -5.662709e-02 | -2.094013e-01 | -4.080170e-01 | -1.210919e-01 | -2.751398e-01 | 5.640248e-01 | -9.997373e-02 | -6.262054e-02 | -1.161920e-01 | 4.724086e-01 | -7.243921e-02 | -1.364306e-01 | -1.142764e-01 | -3.565733e-01 | -3.250463e-02 | -7.699703e-02 | -1.147480e-01 |
| 75% | 5.768967e-01 | 6.381084e-01 | 7.073617e-01 | 8.074995e-01 | -3.699339e-01 | 5.988410e-01 | 8.415754e-01 | 9.466974e-01 | 1.641288e-01 | 1.373302e+00 | 1.073118e+00 | 9.335739e-01 | 1.065804e+00 | 5.694758e-01 | -3.626201e-01 | -3.900919e-01 | 1.166693e+00 | -1.449765e-01 | 1.547064e+00 | -3.987717e-02 | -1.070657e-01 | -5.218705e-01 | -2.307328e-01 | -5.797404e-02 | -2.450360e-01 | -1.759274e-01 | -1.833126e-01 | -1.198331e-01 | -5.422485e-01 | 1.300693e+00 | -5.235265e-02 | -6.548408e-02 | -1.651433e-01 | -1.945800e-01 | -5.217911e-02 | -4.339212e-02 | -2.052042e-01 | -5.592808e-02 | -4.576243e-02 | -4.795384e-02 | -1.732389e-01 | -3.677551e-01 | -5.374915e-02 | -2.563638e-01 | -1.105320e-01 | -4.738354e-02 | -6.386663e-02 | -1.213729e-01 | -1.024749e-01 | -3.888143e-02 | -1.112267e-01 | -4.582836e-02 | -7.218710e-02 | -1.109632e-01 | -1.816853e-01 | -6.286206e-02 | -9.494287e-02 | -9.064081e-02 | -1.913528e-01 | -1.432699e-01 | -2.663435e-01 | -6.487926e-02 | -2.431898e-01 | -1.322902e-01 | -6.798442e-02 | -1.108243e-01 | -1.276124e-01 | -4.353102e-02 | -5.269803e-02 | -1.836891e-01 | -2.152099e-01 | -8.079797e-02 | -3.727063e-01 | -2.569827e-01 | -1.106016e-01 | -1.410242e-01 | -8.377953e-02 | -8.923075e-02 | -2.223483e-01 | 1.078466e+00 | -2.316422e-01 | -2.056255e-01 | -6.840721e-02 | -1.635900e-01 | -1.133139e-01 | -1.517197e-01 | -1.060265e-01 | -2.457179e-01 | -1.853097e-01 | -3.907006e-01 | -1.052845e-01 | -2.300164e-01 | -7.650151e-02 | -1.338815e-01 | -1.040488e-02 | -2.221219e-02 | 5.164423e-01 | -4.587921e-03 | -1.672494e-02 | -3.332857e-02 | -1.110404e-02 | -3.837394e-02 | -1.471552e-02 | -1.646527e-01 | -8.969180e-02 | -1.227052e-01 | -2.866111e-01 | -3.627343e-02 | -1.597514e-01 | -2.422104e-01 | -4.057028e-01 | -1.953196e-01 | 9.590300e-01 | -4.008498e-01 | -4.406164e-01 | 1.041408e+00 | -5.115520e-02 | -3.986998e-01 | -3.015252e-01 | -1.843615e-01 | 1.668428e+00 | -3.454902e-01 | -1.080384e-01 | -1.076675e-01 | 1.301673e+00 | -1.621308e-01 | -2.180625e-01 | -3.117833e-01 | -1.172639e-01 | 1.437697e+00 | -1.803565e-01 | -2.972262e-01 | -2.178884e-01 | -9.274173e-02 | -3.515937e-01 | -5.060453e-01 | -1.871765e-01 | -1.661971e-01 | -2.031266e-01 | -1.904730e-01 | -1.332070e-02 | -1.297756e-02 | -2.534135e-01 | -1.414671e-01 | -1.435757e-01 | -2.674683e-01 | -1.108382e-01 | -2.207875e-01 | -2.280167e-01 | -3.495984e-01 | -2.020730e-01 | -3.005807e-01 | -1.865388e-01 | -3.611375e-01 | -1.597514e-01 | -1.577207e-01 | -1.332070e-02 | -3.111443e-01 | -3.202667e-01 | -1.297756e-02 | -6.499600e-02 | -2.337816e-01 | -2.091430e-01 | -1.861673e-01 | -1.091440e-01 | -5.304797e-01 | -8.940177e-02 | -2.991930e-01 | -5.662709e-02 | -2.094013e-01 | -4.080170e-01 | -1.210919e-01 | -2.751398e-01 | 5.640248e-01 | -9.997373e-02 | -6.262054e-02 | -1.161920e-01 | 4.724086e-01 | -7.243921e-02 | -1.364306e-01 | -1.142764e-01 | -3.565733e-01 | -3.250463e-02 | -7.699703e-02 | -1.147480e-01 |
| max | 2.251473e+00 | 2.900592e+00 | 3.746715e+00 | 1.421225e+00 | 5.689749e+00 | 5.428686e+00 | 2.305484e+00 | 7.005517e+00 | 8.492691e+00 | 2.067813e+00 | 1.348928e+00 | 1.462243e+00 | 1.780477e+00 | 2.284613e+00 | 2.757707e+00 | 2.563498e+00 | 1.166693e+00 | 6.897670e+00 | 1.547064e+00 | 2.507700e+01 | 9.340057e+00 | 1.916184e+00 | 4.334017e+00 | 1.724910e+01 | 4.081033e+00 | 5.684162e+00 | 5.455161e+00 | 8.344942e+00 | 1.844173e+00 | 1.300693e+00 | 1.910123e+01 | 1.527089e+01 | 6.055347e+00 | 5.139274e+00 | 1.916476e+01 | 2.304566e+01 | 4.873195e+00 | 1.788011e+01 | 2.185199e+01 | 2.085339e+01 | 5.772376e+00 | 2.719201e+00 | 1.860495e+01 | 3.900707e+00 | 9.047155e+00 | 2.110437e+01 | 1.565763e+01 | 8.239075e+00 | 9.758484e+00 | 2.571922e+01 | 8.990645e+00 | 2.182055e+01 | 1.385289e+01 | 9.011996e+00 | 5.504021e+00 | 1.590785e+01 | 1.053265e+01 | 1.103256e+01 | 5.225949e+00 | 6.979831e+00 | 3.754550e+00 | 1.541325e+01 | 4.112015e+00 | 7.559137e+00 | 1.470925e+01 | 9.023294e+00 | 7.836227e+00 | 2.297213e+01 | 1.897604e+01 | 5.443982e+00 | 4.646625e+00 | 1.237655e+01 | 2.683078e+00 | 3.891313e+00 | 9.041457e+00 | 7.090983e+00 | 1.193609e+01 | 1.120690e+01 | 4.497448e+00 | 1.078466e+00 | 4.317003e+00 | 4.863209e+00 | 1.461834e+01 | 6.112844e+00 | 8.825044e+00 | 6.591100e+00 | 9.431601e+00 | 4.069708e+00 | 5.396371e+00 | 2.559505e+00 | 9.498073e+00 | 4.347517e+00 | 1.307164e+01 | 7.469290e+00 | 9.610873e+01 | 4.502032e+01 | 5.164423e-01 | 2.179636e+02 | 5.979094e+01 | 3.000429e+01 | 9.005730e+01 | 2.605935e+01 | 6.795546e+01 | 6.073391e+00 | 1.114929e+01 | 8.149612e+00 | 3.489049e+00 | 2.756839e+01 | 6.259724e+00 | 4.128642e+00 | 2.464859e+00 | 5.119815e+00 | 9.590300e-01 | 2.494700e+00 | 2.269548e+00 | 1.041408e+00 | 1.954836e+01 | 2.508153e+00 | 3.316472e+00 | 5.424127e+00 | 1.668428e+00 | 2.894438e+00 | 9.255967e+00 | 9.287854e+00 | 1.301673e+00 | 6.167860e+00 | 4.585841e+00 | 3.207356e+00 | 8.527772e+00 | 1.437697e+00 | 5.544573e+00 | 3.364441e+00 | 4.589505e+00 | 1.078263e+01 | 2.844192e+00 | 1.976108e+00 | 5.342552e+00 | 6.016952e+00 | 4.923038e+00 | 5.250088e+00 | 7.507115e+01 | 7.705610e+01 | 3.946119e+00 | 7.068781e+00 | 6.964969e+00 | 3.738761e+00 | 9.022162e+00 | 4.529243e+00 | 4.385644e+00 | 2.860425e+00 | 4.948706e+00 | 3.326894e+00 | 5.360816e+00 | 2.769028e+00 | 6.259724e+00 | 6.340324e+00 | 7.507115e+01 | 3.213943e+00 | 3.122398e+00 | 7.705610e+01 | 1.538556e+01 | 4.277496e+00 | 4.781417e+00 | 5.371512e+00 | 9.162211e+00 | 1.885086e+00 | 1.118546e+01 | 3.342324e+00 | 1.765939e+01 | 4.775519e+00 | 2.450878e+00 | 8.258188e+00 | 3.634516e+00 | 5.640248e-01 | 1.000263e+01 | 1.596920e+01 | 8.606444e+00 | 4.724086e-01 | 1.380468e+01 | 7.329736e+00 | 8.750714e+00 | 2.804472e+00 | 3.076485e+01 | 1.298751e+01 | 8.714745e+00 |
Come si vede, adesso tutti gli attributi sono stati standardizzati (hanno media nulla e varianza unitaria). Ecco finalmente il training set finale pre elaborato e pronto per l'esecuzione dei modelli di machine learning:
print(train_set_X.shape)
train_set_X.head()
(332564, 185)
| Age_Band_of_Driver | Age_of_Vehicle | Engine_Capacity_.CC. | Year | Did_Police_Officer_Attend_Scene_of_Accident | Latitude | Longitude | Number_of_Casualties | Number_of_Vehicles | Speed_limit | Day_of_Week_sin | Day_of_Week_cos | Time_Interval_sin | Time_Interval_cos | Journey_Purpose_of_Driver_Commuting to/from work | Journey_Purpose_of_Driver_Journey as part of work | Journey_Purpose_of_Driver_Not known | Journey_Purpose_of_Driver_Other | Journey_Purpose_of_Driver_Other/Not known (2005-10) | Journey_Purpose_of_Driver_Pupil riding to/from school | Journey_Purpose_of_Driver_Taking pupil to/from school | Junction_Location_Approaching junction or waiting/parked at junction approach | Junction_Location_Cleared junction or waiting/parked at junction exit | Junction_Location_Entering from slip road | Junction_Location_Entering main road | Junction_Location_Entering roundabout | Junction_Location_Leaving main road | Junction_Location_Leaving roundabout | Junction_Location_Mid Junction - on roundabout or on main road | Junction_Location_Not at or within 20 metres of junction | make_ALFA ROMEO | make_APRILIA | make_AUDI | make_BMW | make_CHEVROLET | make_CHRYSLER | make_CITROEN | make_DAEWOO | make_DAIHATSU | make_DUCATI | make_FIAT | make_FORD | make_HARLEY-DAVIDSON | make_HONDA | make_HYUNDAI | make_IVECO | make_JAGUAR | make_KAWASAKI | make_KIA | make_KTM | make_LAND ROVER | make_LEXUS | make_LONDON TAXIS INT | make_MAZDA | make_MERCEDES | make_MG | make_MINI | make_MITSUBISHI | make_NISSAN | make_OTHERS | make_PEUGEOT | make_PIAGGIO | make_RENAULT | make_ROVER | make_SAAB | make_SEAT | make_SKODA | make_SMART | make_SUBARU | make_SUZUKI | make_TOYOTA | make_TRIUMPH | make_VAUXHALL | make_VOLKSWAGEN | make_VOLVO | make_YAMAHA | Vehicle_Manoeuvre_Changing lane to left | Vehicle_Manoeuvre_Changing lane to right | Vehicle_Manoeuvre_Going ahead left-hand bend | Vehicle_Manoeuvre_Going ahead other | Vehicle_Manoeuvre_Going ahead right-hand bend | Vehicle_Manoeuvre_Moving off | Vehicle_Manoeuvre_Overtaking - nearside | Vehicle_Manoeuvre_Overtaking moving vehicle - offside | Vehicle_Manoeuvre_Overtaking static vehicle - offside | Vehicle_Manoeuvre_Parked | Vehicle_Manoeuvre_Reversing | Vehicle_Manoeuvre_Slowing or stopping | Vehicle_Manoeuvre_Turning left | Vehicle_Manoeuvre_Turning right | Vehicle_Manoeuvre_U-turn | Vehicle_Manoeuvre_Waiting to go - held up | Vehicle_Manoeuvre_Waiting to turn left | Vehicle_Manoeuvre_Waiting to turn right | Vehicle_Type_Agricultural vehicle | Vehicle_Type_Bus or coach (17 or more pass seats) | Vehicle_Type_Car | Vehicle_Type_Electric motorcycle | Vehicle_Type_Goods 7.5 tonnes mgw and over | Vehicle_Type_Goods over 3.5t. and under 7.5t | Vehicle_Type_Goods vehicle - unknown weight | Vehicle_Type_Minibus (8 - 16 passenger seats) | Vehicle_Type_Motorcycle - unknown cc | Vehicle_Type_Motorcycle 125cc and under | Vehicle_Type_Motorcycle 50cc and under | Vehicle_Type_Motorcycle over 125cc and up to 500cc | Vehicle_Type_Motorcycle over 500cc | Vehicle_Type_Other vehicle | Vehicle_Type_Taxi/Private hire car | Vehicle_Type_Van / Goods 3.5 tonnes mgw or under | X1st_Point_of_Impact_Back | X1st_Point_of_Impact_Did not impact | X1st_Point_of_Impact_Front | X1st_Point_of_Impact_Nearside | X1st_Point_of_Impact_Offside | 1st_Road_Class_A | 1st_Road_Class_A(M) | 1st_Road_Class_B | 1st_Road_Class_C | 1st_Road_Class_Motorway | 1st_Road_Class_Unclassified | Junction_Detail_Crossroads | Junction_Detail_Mini-roundabout | Junction_Detail_More than 4 arms (not roundabout) | Junction_Detail_Not at junction or within 20 metres | Junction_Detail_Other junction | Junction_Detail_Private drive or entrance | Junction_Detail_Roundabout | Junction_Detail_Slip road | Junction_Detail_T or staggered junction | Local_Authority_(District)_0 | Local_Authority_(District)_1 | Local_Authority_(District)_10 | Local_Authority_(District)_11 | Local_Authority_(District)_12 | Local_Authority_(District)_13 | Local_Authority_(District)_14 | Local_Authority_(District)_15 | Local_Authority_(District)_16 | Local_Authority_(District)_17 | Local_Authority_(District)_18 | Local_Authority_(District)_19 | Local_Authority_(District)_2 | Local_Authority_(District)_3 | Local_Authority_(District)_4 | Local_Authority_(District)_5 | Local_Authority_(District)_6 | Local_Authority_(District)_7 | Local_Authority_(District)_8 | Local_Authority_(District)_9 | Local_Authority_(Highway)_0 | Local_Authority_(Highway)_1 | Local_Authority_(Highway)_10 | Local_Authority_(Highway)_11 | Local_Authority_(Highway)_12 | Local_Authority_(Highway)_13 | Local_Authority_(Highway)_14 | Local_Authority_(Highway)_15 | Local_Authority_(Highway)_16 | Local_Authority_(Highway)_17 | Local_Authority_(Highway)_18 | Local_Authority_(Highway)_19 | Local_Authority_(Highway)_2 | Local_Authority_(Highway)_3 | Local_Authority_(Highway)_4 | Local_Authority_(Highway)_5 | Local_Authority_(Highway)_6 | Local_Authority_(Highway)_7 | Local_Authority_(Highway)_8 | Local_Authority_(Highway)_9 | Road_Type_Dual carriageway | Road_Type_One way street | Road_Type_Roundabout | Road_Type_Single carriageway | Road_Type_Slip road | Road_Type_Unknown | Weather_Conditions_Fine + high winds | Weather_Conditions_Fine no high winds | Weather_Conditions_Fog or mist | Weather_Conditions_Other | Weather_Conditions_Raining + high winds | Weather_Conditions_Raining no high winds | Weather_Conditions_Snowing + high winds | Weather_Conditions_Snowing no high winds | Weather_Conditions_Unknown | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.576897 | 0.411860 | 0.058077 | 0.500637 | -0.369934 | 0.294340 | -0.594463 | -0.568008 | 0.164129 | -0.015721 | 1.073118 | 0.933574 | 1.731773 | 0.125566 | -0.362620 | 2.563498 | -0.857124 | -0.144976 | -0.646386 | -0.039877 | -0.107066 | -0.521871 | -0.230733 | -0.057974 | -0.245036 | 5.684162 | -0.183313 | -0.119833 | -0.542248 | -0.768821 | -0.052353 | -0.065484 | -0.165143 | -0.19458 | -0.052179 | -0.043392 | -0.205204 | -0.055928 | -0.045762 | -0.047954 | -0.173239 | -0.367755 | -0.053749 | -0.256364 | -0.110532 | -0.047384 | -0.063867 | -0.121373 | -0.102475 | -0.038881 | -0.111227 | -0.045828 | -0.072187 | -0.110963 | -0.181685 | -0.062862 | 10.532650 | -0.090641 | -0.191353 | -0.14327 | -0.266344 | -0.064879 | -0.243190 | -0.13229 | -0.067984 | -0.110824 | -0.127612 | -0.043531 | -0.052698 | -0.183689 | -0.215210 | -0.080798 | -0.372706 | -0.256983 | -0.110602 | -0.141024 | -0.08378 | -0.089231 | -0.222348 | -0.927243 | -0.231642 | -0.205626 | -0.068407 | -0.16359 | -0.113314 | -0.15172 | -0.106027 | -0.245718 | -0.185310 | 2.559505 | -0.105285 | -0.230016 | -0.076502 | -0.133882 | -0.010405 | -0.022212 | 0.516442 | -0.004588 | -0.016725 | -0.033329 | -0.011104 | -0.038374 | -0.014716 | -0.164653 | -0.089692 | -0.122705 | -0.286611 | -0.036273 | -0.159751 | -0.24221 | -0.405703 | 5.119815 | -1.04272 | -0.40085 | -0.440616 | 1.041408 | -0.051155 | -0.3987 | -0.301525 | -0.184361 | -0.599367 | -0.345490 | -0.108038 | -0.107667 | -0.768242 | -0.162131 | -0.218062 | 3.207356 | -0.117264 | -0.695557 | -0.180357 | -0.297226 | -0.217888 | -0.092742 | -0.351594 | -0.506045 | -0.187176 | -0.166197 | -0.203127 | -0.190473 | -0.013321 | -0.012978 | -0.253414 | -0.141467 | -0.143576 | -0.267468 | -0.110838 | -0.220787 | -0.228017 | 2.860425 | -0.202073 | -0.300581 | -0.186539 | -0.361138 | -0.159751 | -0.157721 | -0.013321 | -0.311144 | 3.122398 | -0.012978 | -0.064996 | -0.233782 | -0.209143 | -0.186167 | -0.109144 | -0.530480 | -0.089402 | -0.299193 | -0.056627 | -0.209401 | -0.408017 | -0.121092 | 3.634516 | -1.772972 | -0.099974 | -0.062621 | -0.116192 | -2.116811 | -0.072439 | -0.136431 | -0.114276 | 2.804472 | -0.032505 | -0.076997 | -0.114748 |
| 1 | 0.576897 | -0.266885 | 0.760006 | -0.113088 | 2.659907 | 2.250818 | -1.275829 | -0.568008 | 0.164129 | -0.710233 | 1.348928 | -0.254336 | -0.886720 | -0.288093 | -0.362620 | -0.390092 | 1.166693 | -0.144976 | -0.646386 | -0.039877 | -0.107066 | 1.916184 | -0.230733 | -0.057974 | -0.245036 | -0.175927 | -0.183313 | -0.119833 | -0.542248 | -0.768821 | -0.052353 | -0.065484 | -0.165143 | -0.19458 | -0.052179 | -0.043392 | -0.205204 | -0.055928 | -0.045762 | -0.047954 | -0.173239 | -0.367755 | -0.053749 | -0.256364 | -0.110532 | -0.047384 | -0.063867 | -0.121373 | -0.102475 | -0.038881 | -0.111227 | -0.045828 | -0.072187 | -0.110963 | -0.181685 | -0.062862 | -0.094943 | -0.090641 | -0.191353 | -0.14327 | -0.266344 | -0.064879 | 4.112015 | -0.13229 | -0.067984 | -0.110824 | -0.127612 | -0.043531 | -0.052698 | -0.183689 | -0.215210 | -0.080798 | -0.372706 | -0.256983 | -0.110602 | -0.141024 | -0.08378 | -0.089231 | -0.222348 | -0.927243 | -0.231642 | -0.205626 | -0.068407 | -0.16359 | -0.113314 | -0.15172 | -0.106027 | -0.245718 | -0.185310 | 2.559505 | -0.105285 | -0.230016 | -0.076502 | -0.133882 | -0.010405 | -0.022212 | 0.516442 | -0.004588 | -0.016725 | -0.033329 | -0.011104 | -0.038374 | -0.014716 | -0.164653 | -0.089692 | -0.122705 | -0.286611 | -0.036273 | -0.159751 | -0.24221 | -0.405703 | -0.195320 | -1.04272 | 2.49470 | -0.440616 | -0.960238 | -0.051155 | -0.3987 | 3.316472 | -0.184361 | -0.599367 | -0.345490 | -0.108038 | -0.107667 | -0.768242 | -0.162131 | 4.585841 | -0.311783 | -0.117264 | -0.695557 | -0.180357 | -0.297226 | -0.217888 | -0.092742 | -0.351594 | -0.506045 | -0.187176 | 6.016952 | -0.203127 | -0.190473 | -0.013321 | -0.012978 | -0.253414 | -0.141467 | -0.143576 | -0.267468 | -0.110838 | -0.220787 | -0.228017 | -0.349598 | -0.202073 | -0.300581 | -0.186539 | -0.361138 | 6.259724 | -0.157721 | -0.013321 | -0.311144 | -0.320267 | -0.012978 | -0.064996 | -0.233782 | -0.209143 | -0.186167 | -0.109144 | -0.530480 | -0.089402 | -0.299193 | -0.056627 | -0.209401 | -0.408017 | -0.121092 | -0.275140 | 0.564025 | -0.099974 | -0.062621 | -0.116192 | 0.472409 | -0.072439 | -0.136431 | -0.114276 | -0.356573 | -0.032505 | -0.076997 | -0.114748 |
| 2 | 1.135089 | -0.945630 | 1.168880 | -0.113088 | -0.369934 | 0.776563 | -0.954291 | 2.461402 | 0.164129 | -0.710233 | 1.348928 | -0.254336 | 1.588981 | -0.288093 | 2.757707 | -0.390092 | -0.857124 | -0.144976 | -0.646386 | -0.039877 | -0.107066 | -0.521871 | -0.230733 | -0.057974 | -0.245036 | -0.175927 | -0.183313 | -0.119833 | 1.844173 | -0.768821 | -0.052353 | -0.065484 | -0.165143 | -0.19458 | -0.052179 | -0.043392 | -0.205204 | -0.055928 | -0.045762 | -0.047954 | -0.173239 | -0.367755 | -0.053749 | -0.256364 | -0.110532 | -0.047384 | -0.063867 | -0.121373 | -0.102475 | -0.038881 | -0.111227 | -0.045828 | -0.072187 | -0.110963 | -0.181685 | -0.062862 | -0.094943 | -0.090641 | -0.191353 | -0.14327 | -0.266344 | -0.064879 | -0.243190 | -0.13229 | -0.067984 | -0.110824 | -0.127612 | -0.043531 | -0.052698 | -0.183689 | 4.646625 | -0.080798 | -0.372706 | -0.256983 | -0.110602 | -0.141024 | -0.08378 | -0.089231 | -0.222348 | -0.927243 | -0.231642 | -0.205626 | -0.068407 | -0.16359 | -0.113314 | -0.15172 | -0.106027 | -0.245718 | -0.185310 | 2.559505 | -0.105285 | -0.230016 | -0.076502 | -0.133882 | -0.010405 | -0.022212 | 0.516442 | -0.004588 | -0.016725 | -0.033329 | -0.011104 | -0.038374 | -0.014716 | -0.164653 | -0.089692 | -0.122705 | -0.286611 | -0.036273 | -0.159751 | -0.24221 | -0.405703 | -0.195320 | 0.95903 | -0.40085 | -0.440616 | 1.041408 | -0.051155 | -0.3987 | -0.301525 | -0.184361 | -0.599367 | 2.894438 | -0.108038 | -0.107667 | -0.768242 | -0.162131 | -0.218062 | -0.311783 | -0.117264 | -0.695557 | -0.180357 | -0.297226 | -0.217888 | -0.092742 | -0.351594 | -0.506045 | -0.187176 | -0.166197 | -0.203127 | -0.190473 | -0.013321 | -0.012978 | -0.253414 | -0.141467 | -0.143576 | -0.267468 | -0.110838 | -0.220787 | -0.228017 | 2.860425 | -0.202073 | -0.300581 | -0.186539 | -0.361138 | -0.159751 | -0.157721 | -0.013321 | -0.311144 | -0.320267 | -0.012978 | -0.064996 | -0.233782 | -0.209143 | -0.186167 | -0.109144 | -0.530480 | -0.089402 | 3.342324 | -0.056627 | -0.209401 | -0.408017 | -0.121092 | -0.275140 | 0.564025 | -0.099974 | -0.062621 | -0.116192 | 0.472409 | -0.072439 | -0.136431 | -0.114276 | -0.356573 | -0.032505 | -0.076997 | -0.114748 |
| 3 | 0.576897 | -0.040637 | 1.093423 | 0.193774 | -0.369934 | -0.670391 | 0.854058 | 0.946697 | 0.164129 | -0.710233 | 1.348928 | -0.254336 | 1.780477 | 0.569476 | 2.757707 | -0.390092 | -0.857124 | -0.144976 | -0.646386 | -0.039877 | -0.107066 | -0.521871 | -0.230733 | -0.057974 | 4.081033 | -0.175927 | -0.183313 | -0.119833 | -0.542248 | -0.768821 | -0.052353 | -0.065484 | -0.165143 | -0.19458 | -0.052179 | -0.043392 | -0.205204 | -0.055928 | -0.045762 | -0.047954 | -0.173239 | -0.367755 | -0.053749 | -0.256364 | -0.110532 | -0.047384 | -0.063867 | -0.121373 | -0.102475 | -0.038881 | -0.111227 | -0.045828 | -0.072187 | -0.110963 | -0.181685 | -0.062862 | -0.094943 | -0.090641 | -0.191353 | -0.14327 | -0.266344 | -0.064879 | 4.112015 | -0.13229 | -0.067984 | -0.110824 | -0.127612 | -0.043531 | -0.052698 | -0.183689 | -0.215210 | -0.080798 | -0.372706 | -0.256983 | -0.110602 | -0.141024 | -0.08378 | -0.089231 | -0.222348 | -0.927243 | -0.231642 | -0.205626 | -0.068407 | -0.16359 | -0.113314 | -0.15172 | -0.106027 | -0.245718 | 5.396371 | -0.390701 | -0.105285 | -0.230016 | -0.076502 | -0.133882 | -0.010405 | -0.022212 | 0.516442 | -0.004588 | -0.016725 | -0.033329 | -0.011104 | -0.038374 | -0.014716 | -0.164653 | -0.089692 | -0.122705 | -0.286611 | -0.036273 | -0.159751 | -0.24221 | -0.405703 | -0.195320 | 0.95903 | -0.40085 | -0.440616 | 1.041408 | -0.051155 | -0.3987 | -0.301525 | -0.184361 | -0.599367 | -0.345490 | -0.108038 | -0.107667 | -0.768242 | -0.162131 | -0.218062 | 3.207356 | -0.117264 | -0.695557 | -0.180357 | -0.297226 | -0.217888 | -0.092742 | -0.351594 | 1.976108 | -0.187176 | -0.166197 | -0.203127 | -0.190473 | -0.013321 | -0.012978 | -0.253414 | -0.141467 | -0.143576 | -0.267468 | -0.110838 | -0.220787 | -0.228017 | -0.349598 | -0.202073 | -0.300581 | -0.186539 | -0.361138 | -0.159751 | -0.157721 | -0.013321 | -0.311144 | -0.320267 | -0.012978 | -0.064996 | -0.233782 | -0.209143 | -0.186167 | -0.109144 | 1.885086 | -0.089402 | -0.299193 | -0.056627 | -0.209401 | -0.408017 | -0.121092 | -0.275140 | 0.564025 | -0.099974 | -0.062621 | -0.116192 | -2.116811 | -0.072439 | -0.136431 | -0.114276 | -0.356573 | -0.032505 | -0.076997 | 8.714745 |
| 4 | -1.097680 | -0.266885 | 0.707362 | 0.193774 | -0.369934 | 1.578580 | -0.094655 | -0.568008 | 0.164129 | -0.710233 | 1.348928 | -0.254336 | -0.363543 | 2.054828 | -0.362620 | -0.390092 | 1.166693 | -0.144976 | -0.646386 | -0.039877 | -0.107066 | -0.521871 | -0.230733 | -0.057974 | -0.245036 | 5.684162 | -0.183313 | -0.119833 | -0.542248 | -0.768821 | -0.052353 | -0.065484 | -0.165143 | -0.19458 | -0.052179 | -0.043392 | -0.205204 | -0.055928 | -0.045762 | -0.047954 | -0.173239 | -0.367755 | -0.053749 | -0.256364 | -0.110532 | -0.047384 | -0.063867 | -0.121373 | -0.102475 | -0.038881 | -0.111227 | -0.045828 | -0.072187 | -0.110963 | -0.181685 | -0.062862 | -0.094943 | -0.090641 | -0.191353 | -0.14327 | -0.266344 | -0.064879 | -0.243190 | -0.13229 | -0.067984 | -0.110824 | -0.127612 | -0.043531 | -0.052698 | -0.183689 | -0.215210 | -0.080798 | -0.372706 | 3.891313 | -0.110602 | -0.141024 | -0.08378 | -0.089231 | -0.222348 | 1.078466 | -0.231642 | -0.205626 | -0.068407 | -0.16359 | -0.113314 | -0.15172 | -0.106027 | -0.245718 | -0.185310 | -0.390701 | -0.105285 | -0.230016 | -0.076502 | -0.133882 | -0.010405 | -0.022212 | 0.516442 | -0.004588 | -0.016725 | -0.033329 | -0.011104 | -0.038374 | -0.014716 | -0.164653 | -0.089692 | -0.122705 | -0.286611 | -0.036273 | -0.159751 | -0.24221 | -0.405703 | -0.195320 | -1.04272 | -0.40085 | 2.269548 | 1.041408 | -0.051155 | -0.3987 | -0.301525 | -0.184361 | -0.599367 | -0.345490 | -0.108038 | -0.107667 | -0.768242 | -0.162131 | -0.218062 | 3.207356 | -0.117264 | -0.695557 | -0.180357 | -0.297226 | -0.217888 | -0.092742 | -0.351594 | -0.506045 | -0.187176 | -0.166197 | -0.203127 | -0.190473 | -0.013321 | -0.012978 | -0.253414 | -0.141467 | -0.143576 | -0.267468 | -0.110838 | 4.529243 | -0.228017 | -0.349598 | 4.948706 | -0.300581 | -0.186539 | -0.361138 | -0.159751 | -0.157721 | -0.013321 | -0.311144 | -0.320267 | -0.012978 | -0.064996 | -0.233782 | -0.209143 | -0.186167 | -0.109144 | -0.530480 | -0.089402 | -0.299193 | -0.056627 | -0.209401 | -0.408017 | -0.121092 | 3.634516 | -1.772972 | -0.099974 | -0.062621 | -0.116192 | 0.472409 | -0.072439 | -0.136431 | -0.114276 | -0.356573 | -0.032505 | -0.076997 | -0.114748 |
Alla fine della fase di pre-processing, non resta che realizzare un'unica pipeline che riassuma tutte le fasi di processamento del dataset, così che in un solo colpo tali fasi è possibile applicarle sia al training set ma soprattutto al test set; in modo da rendere il test set compatibile con il train set.
Verranno create le classi WrapperTransformer e WrapperTransformer2 che serviranno per il wrapping dei trasformatori custom creati in precedenza; in modo da poter sfruttare le trasformazioni passando tra gli step della pipeline non solo il singolo dataset X ma anche la classe target y. In particolare la prima classe è stata realizzata per i transformer custom e la seconda per altri trasformatori quali ad esempio un ColumnTransformer:
class WrapperTransformer(BaseEstimator, TransformerMixin):
def __init__(self, transformer):
self.transformer = transformer
def transform(self,X,y=None):
if isinstance(X, tuple):
X, y = X
X['Accident_Severity'] = y
X2 = self.transformer.transform(X)
yy = X2['Accident_Severity']
X.drop('Accident_Severity', axis=1, inplace=True)
X2.drop('Accident_Severity', axis=1, inplace=True)
return X2, yy
return self.transformer.transform(X)
def fit(self, X, y=None):
if isinstance(X, tuple):
X, y = X
X['Accident_Severity'] = y
self.transformer.fit(X=X)
X.drop('Accident_Severity', axis=1, inplace=True)
else:
self.transformer.fit(X=X)
return self
class WrapperTransformer2(BaseEstimator, TransformerMixin):
def __init__(self, transformer):
self.transformer = transformer
def transform(self,X,y=None):
ver=False
if isinstance(X, tuple):
X, y = X
ver=True
X2 = self.transformer.transform(X)
if ver:
return X2, y
return X2
def fit(self, X, y=None):
if isinstance(X, tuple):
X, y = X
self.transformer.fit(X)
return self
A questo punto non resta che costruire la pipeline. In particolare verranno costruite due pipeline: full_pipeline_train e full_pipeline_test. Si sono dovute realizzare due pipeline perchè per quanto riguarda il processamento del training set, sono presenti due step che non sono necessari per il testing set, ovvero l'operazione di rimozione degli outliers e quella di undersampling per il problema della classe sbilanciata. A parte tale differenza, per il resto le pipeline sono divise in:
Da notare l'aspetto importante: anche se sono presenti due pipeline, si effettua lo stesso solamente la fit (o nel caso fit_transform) sul training set con la pipeline full_pipeline_train; e la transform sul testing set con la pipeline full_pipeline_test. Questo è possibile perchè alla fine le due pipeline hanno in comune il riferimento della pipeline per le transformazioni (data_transformation_pipeline); mentre per la data_cleaning_pipeline anche se non è in comune, esse non effettuano operazioni sulla fit ma solo sulla transform.
colToDrop = ['Driver_IMD_Decile', 'model', '2nd_Road_Class', '2nd_Road_Number',
'LSOA_of_Accident_Location', 'Junction_Control', 'Date', 'Location_Easting_OSGR',
'Location_Northing_OSGR', 'Accident_Index', 'Vehicle_Reference', 'Police_Force',
'1st_Road_Number']
featureSelection = ['Was_Vehicle_Left_Hand_Drive', 'InScotland',
'Pedestrian_Crossing-Human_Control', 'Towing_and_Articulation', 'Urban_or_Rural_Area',
'Vehicle_Location.Restricted_Lane', 'Carriageway_Hazards', 'Special_Conditions_at_Site',
'Hit_Object_in_Carriageway', 'Sex_of_Driver', 'Skidding_and_Overturning',
'Hit_Object_off_Carriageway', 'Propulsion_Code', 'Road_Surface_Conditions', 'Light_Conditions',
'Driver_Home_Area_Type', 'Vehicle_Leaving_Carriageway', 'Pedestrian_Crossing-Physical_Facilities']
days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
categoricalRemaind = ['Journey_Purpose_of_Driver', 'Junction_Location', 'make', 'Vehicle_Manoeuvre',
'Vehicle_Type', 'X1st_Point_of_Impact', '1st_Road_Class', 'Junction_Detail', 'Local_Authority_(District)',
'Local_Authority_(Highway)', 'Road_Type', 'Weather_Conditions']
col_outliers = ['Age_of_Vehicle', 'Engine_Capacity_.CC.', 'Number_of_Casualties', 'Number_of_Vehicles']
data_cleaning_pipeline_after = Pipeline([
('replaceMissingToNaN', ReplaceValuesTransformer("Data missing or out of range", np.NaN)),
('dropColumns', ColumnDropperTransformer(colToDrop)),
('dropRowsAnyNaN', RowsDropperTransformer()),
])
data_cleaning_pipeline_before = Pipeline([
('featureSelection', WrapperTransformer(ColumnDropperTransformer(featureSelection))),
('binaryProblem', FunctionTransformer(transformAccidentSverity, validate=False)),
])
data_cleaning_pipeline = Pipeline([
('data_cleaning_pipeline_after', data_cleaning_pipeline_after),
('dropRowsOutliers', RowsDropperOutliersTransformer(col_outliers)),
('data_cleaning_pipeline_before', data_cleaning_pipeline_before),
])
data_cleaning_pipeline_test = Pipeline([
('data_cleaning_pipeline_after', data_cleaning_pipeline_after),
('data_cleaning_pipeline_before', data_cleaning_pipeline_before),
])
dimensionality_pipeline = Pipeline([
('timeToTimeInterval', WrapperTransformer(TimeTransformer())),
('ageDriverDeleteValues', WrapperTransformer(RowsDropperTransformer('Age_Band_of_Driver'))),
('speedLimitDeleteValues', WrapperTransformer(RowsDropperTransformer('Speed_limit'))),
('localDistrictClustering', WrapperTransformer(ClusteringReplaceValuesTransformer("Local_Authority_(District)"))),
('localHighwayClustering', WrapperTransformer(ClusteringReplaceValuesTransformer("Local_Authority_(Highway)"))),
('makeOthers', WrapperTransformer(VehiclesFeatureGroupNameTransformer())),
])
encoding_pipeline = Pipeline([
("dayWeekEncoder", WrapperTransformer(CircularEncoder(feature="Day_of_Week", cat=[days], number=7))),
("timeIntervalEncoder", WrapperTransformer(CircularEncoder())),
('colTransformer', WrapperTransformer2(ColumnTransformer([
("ageDriverEncoder", OrdinalEncoder(), ['Age_Band_of_Driver']),
("oneHotEncoderOthers", OneHotEncoder(sparse=False), categoricalRemaind),
],remainder='passthrough'))),
])
scaling_pipeline = Pipeline([
('standardScaler', WrapperTransformer2(StandardScaler())),
# ('minMaxScaler', WrapperTransformer2(MinMaxScaler())),
#('robustScaler', WrapperTransformer2(RobustScaler())),
])
data_transformation_pipeline = Pipeline([
('dimensionality', dimensionality_pipeline),
('encoding', encoding_pipeline),
('scaling', scaling_pipeline),
])
full_pipeline_test = Pipeline([
('dataCleaning', data_cleaning_pipeline_test),
('dataTransformation', data_transformation_pipeline),
])
full_pipeline_train = Pipeline([
('dataCleaning', data_cleaning_pipeline),
('underSampling', FunctionTransformer(underSampling, validate=False)),
('dataTransformation', data_transformation_pipeline),
])
Per concludere questa sezione, si rendono i dataset di train e test belli e pronti per le fasi successive in cui verranno eseguiti i modelli di data mininig (da notare che il training set è già pronto perchè le trasformazioni sono state eseguite passo passo, però per una questione illustrativa verrà trasformato il training set iniziale senza trasformazioni con la pipeline):
print("Prima training set pronto -->", train_set_X.shape)
print("Prima training set iniziale -->", train_set_iniziale.shape)
X_train, y_train = full_pipeline_train.fit_transform(train_set_iniziale)
print("Dopo X_train -->", X_train.shape)
print("Dopo y_train -->", y_train.shape)
Prima training set pronto --> (332564, 185) Prima training set iniziale --> (2037823, 56) Dopo X_train --> (332564, 185) Dopo y_train --> (332564,)
print("Prima testing set iniziale -->", test_set.shape)
X_test, y_test = full_pipeline_test.transform(test_set)
print("Dopo X_test -->", X_test.shape)
print("Dopo y_test -->", y_test.shape)
Prima testing set iniziale --> (20585, 56) Dopo X_test --> (14325, 185) Dopo y_test --> (14325,)
Ecco i dataset pronti train e test con le rispettive classi target:
X_train, y_train
(array([[ 0.57689672, -0.36262012, 2.56349817, ..., 0.9335739 ,
1.73177307, 0.12556571],
[ 0.57689672, -0.36262012, -0.39009195, ..., -0.25433556,
-0.88672032, -0.28809265],
[ 1.1350888 , 2.75770688, -0.39009195, ..., -0.25433556,
1.58898073, -0.28809265],
...,
[ 0.01870465, -0.36262012, 2.56349817, ..., -0.25433556,
0.35113021, -1.1456611 ],
[ 0.01870465, -0.36262012, -0.39009195, ..., 0.9335739 ,
-0.01881193, -1.08721922],
[ 1.1350888 , -0.36262012, 2.56349817, ..., 0.9335739 ,
1.73177307, 0.12556571]]),
0 0
1 0
2 0
3 0
4 0
..
332573 1
332574 1
332575 1
332576 1
332577 1
Name: Accident_Severity, Length: 332564, dtype: uint8)
X_test, y_test
(array([[ 0.01870465, -0.36262012, 2.56349817, ..., -0.25433556,
-0.88672032, 1.42704425],
[-1.65587158, -0.36262012, -0.39009195, ..., 1.46224334,
-1.07821646, 0.5694758 ],
[ 0.01870465, -0.36262012, 2.56349817, ..., 1.46224334,
-1.07821646, 0.5694758 ],
...,
[ 0.57689672, 2.75770688, -0.39009195, ..., -0.25433556,
-1.07821646, 0.5694758 ],
[-0.53948743, -0.36262012, 2.56349817, ..., -0.25433556,
0.35113021, -1.1456611 ],
[ 0.57689672, -0.36262012, 2.56349817, ..., 0.9335739 ,
-0.01881193, -1.08721922]]),
1755336 0
253404 0
1924463 0
286093 0
2021059 0
..
261461 0
236224 0
1065003 0
356598 0
1018300 0
Name: Accident_Severity, Length: 14325, dtype: uint8)
In questa fase verranno addestrati più modelli per la classificazione, per trovare il modello che generalizzi meglio. Essi saranno valutati attraverso la tecnica KFold Cross Validation. Dove il numero di fold sarà pari a 3 per questioni di costo temporale dell'esecuzione. Ogni modello sarà il migliore della loro rispettiva classe di ipotesi, perchè per ognuno verrà scelto il migliore sulla base della migliore combinazione degli iperparametri, attraverso l'ausilio della GridSearchCV.
Di seguito è descritta la funzione compute_performance che data la lista dei modelli scelti, ritorna un dizionario che, per ogni modello riporta i suoi valori di performance in termini di: accuracy, precision, recall, f1 e auc. Da notare che tali funzioni di score saranno calcolate su un validation set creato ad hoc.
Di seguito sono presenti le griglie adottate per la Grid Search per ogni modello. Dopo di ciò si addestreranno tali modelli e si sceglieranno i migliori iperparametri dei modelli sulla base del valore di accuracy (si ricorda che in questo caso il training set è bilanciato). I modelli calcolati saranno inseriti nella lista estimators.
estimators=[]
# Logistic Regression
grid_reg_log = {
'C': [0.1, 1.0, 10, 100],
'max_iter': [100, 200]
}
# Decision Tree
grid_dec_tree = {
'max_depth': [10, 20],
'min_samples_split': [5, 10],
'min_samples_leaf': [2, 4],
}
# Bernoulli Naive Bayes
grid_BernoulliNB = {
'alpha': [0.5, 1.0],
'binarize': [0.5, 1.0],
}
#KNN
grid_KNN = {
'n_neighbors': [3, 5, 7, 9],
'weights': ['uniform', 'distance'],
'p': [1, 2]
}
#Multi-layer perceptron
grid_MLP = {
'hidden_layer_sizes': [(10,)],
'activation': ['logistic', 'relu'],
'solver': ['adam', 'lbfgs'],
'alpha': [0.001, 0.01],
'learning_rate': ['adaptive'],
}
#SGD Classifier
grid_SGD = {
'loss': ['hinge', 'log'],
'penalty': ['l2', 'l1'],
'alpha': [0.001, 0.1, 1.0],
'max_iter': [1000, 10000],
'tol': [0.01]
}
# Random forest
grid_Random_forest = {
'n_estimators': [50, 500],
'max_depth': [10, 20],
'min_samples_split': [5, 10],
'min_samples_leaf': [2, 4]
}
# Ada Boost
grid_Ada_Boost = {
'base_estimator__max_depth': [3, 5, 10],
'n_estimators': [50, 100],
'learning_rate': [0.1, 1, 2]
}
# XGBoost
grid_XGBoost = {
'max_depth': [3, 5, 10],
'n_estimators': [50, 100],
'learning_rate': [0.1, 1, 2],
'subsample': [0.5, 0.9],
'colsample_bytree': [0.5],
'gamma': [0, 1, 5]
}
# Logistic Regression
filename = './models/log_reg_cv.sav'
# clf = LogisticRegression()
# grid_search = GridSearchCV(
# estimator=clf,
# param_grid=grid_log_reg,
# cv=3,
# scoring="accuracy",
# n_jobs=-1
# )
# grid_result = grid_search.fit(X_train, y_train)
# logreg_cv = grid_search.best_estimator_
# print(grid_search.best_estimator_)
# save the model to disk
# pickle.dump(logreg_cv, open(filename, 'wb'))
#load the model from disk
logreg_cv = pickle.load(open(filename, 'rb'))
estimators.append(logreg_cv)
# Decision Tree
filename = './models/dec_tree_cv.sav'
# clf = DecisionTreeClassifier()
# grid_search = GridSearchCV(
# estimator=clf,
# param_grid=grid_dec_tree,
# cv=3,
# scoring="accuracy",
# n_jobs=-1
# )
# grid_result = grid_search.fit(X_train, y_train)
# dec_tree_cv = grid_search.best_estimator_
# print(grid_search.best_estimator_)
# save the model to disk
# pickle.dump(dec_tree_cv, open(filename, 'wb'))
#load the model from disk
dec_tree_cv = pickle.load(open(filename, 'rb'))
estimators.append(dec_tree_cv)
# Bernoulli Naive Bayes
filename = './models/bernoulliNB_cv.sav'
# clf = BernoulliNB()
# grid_search = GridSearchCV(
# estimator=clf,
# param_grid=grid_BernoulliNB,
# cv=3,
# scoring="accuracy",
# n_jobs=-1
# )
# grid_search.fit(X_train, y_train)
# bernoulli_NB_cv = grid_search.best_estimator_
# print(grid_search.best_estimator_)
# save the model to disk
# pickle.dump(bernoulli_NB_cv, open(filename, 'wb'))
#load the model from disk
bernoulli_NB_cv = pickle.load(open(filename, 'rb'))
estimators.append(bernoulli_NB_cv)
# KNN
filename = './models/KNN_cv.sav'
# clf = KNeighborsClassifier()
# grid_search = GridSearchCV(
# estimator=clf,
# param_grid=grid_KNN,
# cv=3,
# scoring="accuracy",
# n_jobs=-1
# )
# grid_search.fit(X_train, y_train)
# KNN_cv = grid_search.best_estimator_
# print(grid_search.best_estimator_)
# save the model to disk
# pickle.dump(KNN_cv, open(filename, 'wb'))
#load the model from disk
KNN_cv = pickle.load(open(filename, 'rb'))
estimators.append(KNN_cv)
#Multi-layer perceptron
filename = './models/MLPClassifier_cv.sav'
# clf = MLPClassifier()
# grid_search = GridSearchCV(
# estimator=clf,
# param_grid=grid_MLP,
# cv=3,
# scoring="accuracy",
# n_jobs=-1
# )
# grid_search.fit(X_train, y_train)
# mlp_cv = grid_search.best_estimator_
# print(grid_search.best_estimator_)
# save the model to disk
# pickle.dump(mlp_cv, open(filename, 'wb'))
#load the model from disk
mlp_cv = pickle.load(open(filename, 'rb'))
estimators.append(mlp_cv)
#SGD Classifier
filename = './models/SGD_cv.sav'
# clf = SGDClassifier()
# grid_search = GridSearchCV(
# estimator=clf,
# param_grid=grid_SGD,
# cv=3,
# scoring="accuracy",
# n_jobs=-1
# )
# grid_search.fit(X_train, y_train)
# sgd_cv = grid_search.best_estimator_
# print(grid_search.best_estimator_)
# save the model to disk
# pickle.dump(sgd_cv, open(filename, 'wb'))
#load the model from disk
sgd_cv = pickle.load(open(filename, 'rb'))
estimators.append(sgd_cv)
# Random forest
filename = './models/Random_forest_cv.sav'
# clf = RandomForestClassifier()
# grid_search = GridSearchCV(
# estimator=clf,
# param_grid=grid_Random_forest,
# cv=3,
# scoring="accuracy",
# n_jobs=-1
# )
# grid_search.fit(X_train, y_train)
# rf_cv = grid_search.best_estimator_
# print(grid_search.best_estimator_)
# save the model to disk
# pickle.dump(rf_cv, open(filename, 'wb'))
#load the model from disk
rf_cv = pickle.load(open(filename, 'rb'))
estimators.append(rf_cv)
# Ada Boost
filename = './models/Ada_boost_cv.sav'
# clf = AdaBoostClassifier()
# grid_search = GridSearchCV(
# estimator=clf,
# param_grid=grid_Ada_Boost,
# cv=3,
# scoring="accuracy",
# n_jobs=-1
# )
# grid_search.fit(X_train, y_train)
# adaBoost_cv = grid_search.best_estimator_
# print(grid_search.best_estimator_)
# save the model to disk
# pickle.dump(adaBoost_cv, open(filename, 'wb'))
#load the model from disk
adaBoost_cv = pickle.load(open(filename, 'rb'))
estimators.append(adaBoost_cv)
# XGBoost
filename = './models/XGboost_cv.sav'
# clf = xgb.XGBClassifier()
# grid_search = GridSearchCV(
# estimator=clf,
# param_grid=grid_XGBoost,
# cv=3,
# scoring="accuracy",
# n_jobs=-1
# )
# grid_search.fit(X_train, y_train)
# XGBoost_cv = grid_search.best_estimator_
# print(grid_search.best_estimator_)
# save the model to disk
# pickle.dump(XGBoost_cv, open(filename, 'wb'))
#load the model from disk
XGBoost_cv = pickle.load(open(filename, 'rb'))
estimators.append(XGBoost_cv)
Nella lista estimators sono presenti i modelli migliori per la loro rispettiva classe di ipotesi, calcolati mediante GridSearch su cross validation per la scelta dei migliori iperparametri. Adesso per valutare quale sia il migliore tra di essi, si farà uso di un validation set diviso dal training set, e si effetturà la valutazione mediante la funzione compute_performance che data la lista dei modelli scelti, restituisce un dizionario che, per ogni modello riporta i suoi valori di performance in termini di: accuracy, precision, recall, f1 e auc.
X_train2, X_validation, y_train2, y_validation = train_test_split(X_train, y_train, test_size=0.2, random_state=42)
X_train2.shape, X_validation.shape, y_train2.shape, y_validation.shape
((266051, 185), (66513, 185), (266051,), (66513,))
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import f1_score
from sklearn.metrics import roc_auc_score
from sklearn.metrics import accuracy_score
def compute_performance(estimators, X_validation=X_validation, y_validation=y_validation):
score_dict = {}
for e in estimators:
score_dict[e.__class__.__name__] = {}
accuracy = accuracy_score(y_validation, e.predict(X_validation))
score_dict[e.__class__.__name__]['accuracy'] = accuracy
precision = precision_score(y_validation, e.predict(X_validation))
score_dict[e.__class__.__name__]['precision'] = precision
recall = recall_score(y_validation, e.predict(X_validation))
score_dict[e.__class__.__name__]['recall'] = recall
f1 = f1_score(y_validation, e.predict(X_validation))
score_dict[e.__class__.__name__]['f1'] = f1
auc = roc_auc_score(y_validation, e.predict(X_validation))
score_dict[e.__class__.__name__]['auc'] = auc
return score_dict
estimators
[LogisticRegression(max_iter=200, solver='liblinear'),
DecisionTreeClassifier(criterion='entropy', max_depth=20, min_samples_leaf=2,
min_samples_split=5, splitter='random'),
BernoulliNB(alpha=0.5, binarize=0.5),
KNeighborsClassifier(p=1, weights='distance'),
MLPClassifier(alpha=0.01, hidden_layer_sizes=(10,), learning_rate='adaptive'),
SGDClassifier(alpha=0.1, tol=0.01),
RandomForestClassifier(criterion='entropy', max_depth=20, max_features='sqrt',
min_samples_leaf=2, min_samples_split=5,
n_estimators=50),
AdaBoostClassifier(base_estimator=DecisionTreeClassifier(max_depth=5),
learning_rate=0.5)]
filename = './score/score.csv'
# score_dict = compute_performance(estimators)
# # save to disk
# pickle.dump(score_dict, open(filename, 'wb'))
# load the model from disk
score_dict = pickle.load(open(filename, 'rb'))
df_score = pd.DataFrame(data=score_dict)
df_score
| LogisticRegression | DecisionTreeClassifier | BernoulliNB | KNeighborsClassifier | MLPClassifier | SGDClassifier | RandomForestClassifier | AdaBoostClassifier | XGBClassifier | |
|---|---|---|---|---|---|---|---|---|---|
| accuracy | 0.691551 | 0.753472 | 0.662037 | 0.675612 | 0.776042 | 0.646123 | 0.770544 | 0.773438 | 0.775752 |
| precision | 0.699158 | 0.809760 | 0.681582 | 0.668640 | 0.861912 | 0.671886 | 0.849663 | 0.845647 | 0.845540 |
| recall | 0.672454 | 0.662616 | 0.608218 | 0.701623 | 0.657407 | 0.571181 | 0.657407 | 0.668981 | 0.674769 |
| f1 | 0.685546 | 0.728835 | 0.642813 | 0.684735 | 0.745896 | 0.617454 | 0.741272 | 0.747011 | 0.750563 |
| auc | 0.691551 | 0.753472 | 0.662037 | 0.644735 | 0.776042 | 0.646123 | 0.770544 | 0.773438 | 0.775752 |
ax = df_score.plot(kind='bar', rot=0, figsize=(20,10))
ax.set_ylabel('Metriche di performance')
ax.set_xlabel('classificatori')
ax.set_title('Performance dei classificatori')
for p in ax.containers:
ax.bar_label(p, label_type="edge", labels=[f"{v:.1%}" for v in p.datavalues], fontsize=12)
plt.show()
Le prestazioni appena valutate, in generale non sono molto soddisfacenti. Dopo molte modifiche iterative in tutte le fasi descritte in precedenza, si è arrivati ad una conclusione: cambiare l'algoritmo di undersampling per il bilanciamento delle classi. L'idea è quella di provare con un algortimo di undersampling diverso dal RandomUnderSampling. In particolare l'algoritmo che si adotterà sarà il Near-Miss.
L'algoritmo di undersampling Near-Miss presenta 3 diverse varianti. La variante che verrà utilizzata sarà la variante 1 (Near-Miss v1). NearMiss-1 seleziona i campioni positivi (campioni da sottocampionare) per i quali la distanza media dagli N campioni più vicini della classe negativa (classe minoritaria) è la più piccola. Nel caso in figura verrà eliminato il punto + in basso:

Per maggiori dettagli e approfondimenti si riporta al seguente link: https://imbalanced-learn.org/stable/under_sampling.html
A questo punto di seguito si riporta il nuovo metodo di undersampling che verrà richiamato all'interno di un FunctionTransformer nella nuova pipeline:
def underSampling_nearMiss(df):
X, y = df
rus = NearMiss(version=1, n_neighbors=3)
X, y = rus.fit_resample(X, y)
return X, y
Si modifica quindi la pipeline per l'elaborazione del training set (full_pipeline_train), aggiornando il metodo di undersampling. Da notare che quest'ultimo lavora solamente con input numerici, per tale ragione si è deciso di inseriro a monte della pipeline di trasformazione dataTransformation:
full_pipeline_train = Pipeline([
('dataCleaning', data_cleaning_pipeline),
('dataTransformation', data_transformation_pipeline),
('underSampling_nearMiss', FunctionTransformer(underSampling_nearMiss, validate=False)),
])
Si ricostruiscono il nuovo training set e tasting set:
filename1 = './set/X_train_post_processing.sav'
filename2 = './set/y_train_post_processing.sav'
print("Prima training set iniziale -->", train_set_iniziale.shape)
#X_train, y_train = full_pipeline_train.fit_transform(train_set_iniziale)
#load the training set from disk
X_train = pickle.load(open(filename1, 'rb'))
y_train = pickle.load(open(filename2, 'rb'))
print("Dopo X_train -->", X_train.shape)
print("Dopo y_train -->", y_train.shape)
Prima training set iniziale --> (2037823, 56) Dopo X_train --> (332560, 188) Dopo y_train --> (332560,)
filename1 = './set/X_test_post_processing.sav'
filename2 = './set/y_test_post_processing.sav'
print("Prima testing set iniziale -->", test_set.shape)
#X_test, y_test = full_pipeline_test.transform(test_set)
#load the training set from disk
X_test = pickle.load(open(filename1, 'rb'))
y_test = pickle.load(open(filename2, 'rb'))
print("Dopo X_test -->", X_test.shape)
print("Dopo y_test -->", y_test.shape)
Prima testing set iniziale --> (20585, 56) Dopo X_test --> (14325, 188) Dopo y_test --> (14325,)
A questo punto non resta che riaddetrare i modelli, ripetendo esattamente i passaggi fatti in precedenza. Da notare che in questo caso si dovrebbero ricalcolare i migliori iperparametri per ogni modello siccome è cambiato totalmente il training set, invece, consapevolmente si è deciso di utilizzare gli stessi iperparametri calcolati nei passaggi precedenti per motivi di velocità di esecuzione.
estimators2=[]
# Logistic Regression
filename = './models_post_processing/log_reg_cv.sav'
# logreg_cv = logreg_cv.fit(X_train, y_train)
# save the model to disk
# pickle.dump(logreg_cv, open(filename, 'wb'))
#load the model from disk
logreg_cv = pickle.load(open(filename, 'rb'))
estimators2.append(logreg_cv)
# Decision Tree
filename = './models_post_processing/dec_tree_cv.sav'
# dec_tree_cv = dec_tree_cv.fit(X_train, y_train)
# save the model to disk
# pickle.dump(dec_tree_cv, open(filename, 'wb'))
#load the model from disk
dec_tree_cv = pickle.load(open(filename, 'rb'))
estimators2.append(dec_tree_cv)
# Bernoulli Naive Bayes
filename = './models_post_processing/bernoulliNB_cv.sav'
# bernoulli_NB_cv = bernoulli_NB_cv.fit(X_train, y_train)
# save the model to disk
# pickle.dump(bernoulli_NB_cv, open(filename, 'wb'))
#load the model from disk
bernoulli_NB_cv = pickle.load(open(filename, 'rb'))
estimators2.append(bernoulli_NB_cv)
# KNN
filename = './models_post_processing/KNN_cv.sav'
# KNN_cv = KNN_cv.fit(X_train, y_train)
# save the model to disk
# pickle.dump(KNN_cv, open(filename, 'wb'))
#load the model from disk
KNN_cv = pickle.load(open(filename, 'rb'))
estimators2.append(KNN_cv)
#Multi-layer perceptron
filename = './models_post_processing/MLPClassifier_cv.sav'
# mlp_cv = mlp_cv.fit(X_train, y_train)
# save the model to disk
# pickle.dump(mlp_cv, open(filename, 'wb'))
#load the model from disk
mlp_cv = pickle.load(open(filename, 'rb'))
estimators2.append(mlp_cv)
#SGD Classifier
filename = './models_post_processing/SGD_cv.sav'
# sgd_cv = sgd_cv.fit(X_train, y_train)
# save the model to disk
# pickle.dump(sgd_cv, open(filename, 'wb'))
#load the model from disk
sgd_cv = pickle.load(open(filename, 'rb'))
estimators2.append(sgd_cv)
# Random forest
filename = './models_post_processing/Random_forest_cv.sav'
# rf_cv = rf_cv.fit(X_train, y_train)
# save the model to disk
# pickle.dump(rf_cv, open(filename, 'wb'))
#load the model from disk
rf_cv = pickle.load(open(filename, 'rb'))
estimators2.append(rf_cv)
# Ada Boost
filename = './models_post_processing/Ada_boost_cv.sav'
# adaBoost_cv = adaBoost_cv.fit(X_train, y_train)
# save the model to disk
# pickle.dump(adaBoost_cv, open(filename, 'wb'))
#load the model from disk
adaBoost_cv = pickle.load(open(filename, 'rb'))
estimators2.append(adaBoost_cv)
# XGBoost
filename = './models_post_processing/XGboost_cv.sav'
# XGBoost_cv = XGBoost_cv.fit(X_train, y_train)
# save the model to disk
# pickle.dump(XGBoost_cv, open(filename, 'wb'))
#load the model from disk
XGBoost_cv = pickle.load(open(filename, 'rb'))
estimators2.append(XGBoost_cv)
estimators2
[LogisticRegression(max_iter=200, solver='liblinear'),
DecisionTreeClassifier(criterion='entropy', max_depth=20, min_samples_leaf=2,
min_samples_split=5, splitter='random'),
BernoulliNB(alpha=0.5, binarize=0.5),
KNeighborsClassifier(p=1, weights='distance'),
MLPClassifier(alpha=0.01, hidden_layer_sizes=(10,), learning_rate='adaptive'),
SGDClassifier(alpha=0.1, tol=0.01),
RandomForestClassifier(criterion='entropy', max_depth=20, max_features='sqrt',
min_samples_leaf=2, min_samples_split=5,
n_estimators=50),
AdaBoostClassifier(base_estimator=DecisionTreeClassifier(max_depth=5),
learning_rate=0.5)]
Anche in questo caso si farà uso di un validation set diviso dal training set, e si effetturà la valutazione mediante la funzione compute_performance.
X_train2, X_validation, y_train2, y_validation = train_test_split(X_train, y_train, test_size=0.2, random_state=42)
X_train2.shape, X_validation.shape, y_train2.shape, y_validation.shape
((266048, 188), (66512, 188), (266048,), (66512,))
filename = './score/score2.csv'
# score_dict2 = compute_performance(estimators2)
# # save to disk
# pickle.dump(score_dict2, open(filename, 'wb'))
# load the model from disk
score_dict2 = pickle.load(open(filename, 'rb'))
df_score2 = pd.DataFrame(data=score_dict2)
df_score2
| BernoulliNB | DecisionTreeClassifier | LogisticRegression | MLPClassifier | SGDClassifier | RandomForestClassifier | AdaBoostClassifier | KNeighborsClassifier | XGBClassifier | |
|---|---|---|---|---|---|---|---|---|---|
| accuracy | 0.737521 | 0.817477 | 0.779258 | 0.866941 | 0.726455 | 0.868370 | 0.865483 | 0.725612 | 0.863198 |
| precision | 0.767884 | 0.898759 | 0.807648 | 0.924287 | 0.821933 | 0.939318 | 0.916427 | 0.778640 | 0.917599 |
| recall | 0.681459 | 0.715891 | 0.733588 | 0.799597 | 0.578734 | 0.787850 | 0.804555 | 0.691623 | 0.798305 |
| f1 | 0.722095 | 0.796970 | 0.768838 | 0.857433 | 0.679220 | 0.856942 | 0.856855 | 0.732556 | 0.853805 |
| auc | 0.737567 | 0.817559 | 0.779295 | 0.866996 | 0.726575 | 0.868435 | 0.865532 | 0.692556 | 0.863250 |
Si plottano i risultati ottenuti:
ax = df_score2.plot(kind='bar', rot=0, figsize=(20,10))
ax.set_ylabel('Metriche di performance')
ax.set_xlabel('classificatori')
ax.set_title('Performance dei classificatori')
plt.legend(loc="lower center")
for p in ax.containers:
ax.bar_label(p, label_type="edge", labels=[f"{v:.1%}" for v in p.datavalues], fontsize=12)
plt.show()
Come si può vedere, i risultati emersi sono migliori di quelli in precedenza. A questo punto l'ultimo passo che rimane, è quello di selzionare il classificatore che performa meglio sul validation set in termini di accuracy, dato che il validation set è bilanciato, è valutare le performance definitive sui dati reali che il classificatore non ha mai visto, ovvero il test set iniziale.
first_row = df_score2.iloc[0]
max_idx = first_row.idxmax()
print(max_idx)
max_col_name = df_score2[max_idx]
print(max_col_name)
max_value = first_row[max_idx]
print("Il valore massimo di accuracy è", max_value, "dato dal classificatore", max_idx)
RandomForestClassifier accuracy 0.868370 precision 0.939318 recall 0.787850 f1 0.856942 auc 0.868435 Name: RandomForestClassifier, dtype: float64 Il valore massimo di accuracy è 0.8683696175126293 dato dal classificatore RandomForestClassifier
best_estimator = estimators2[6]
best_estimator
RandomForestClassifier(criterion='entropy', max_depth=20, max_features='sqrt',
min_samples_leaf=2, min_samples_split=5,
n_estimators=50)
best_estimator corrisponde al classificatore con il valore più alto di accuracy.
A questo punto non resta da valutare le performance finali del migliore classificatore scelto nella fase di model selction, con i dati presenti nel test set pre elaborati dalla pipeline per il test set. Per fare ciò si farà uso ancora una volta del metodo compute_performance, passando in ingresso non il validation set bensì il test set. Si farà la stessa cosa con il training set, in modo tale anche da valutare se il modello presenta un elevato livello di overfitting.
filename = './score/score_test.csv'
# score_dict_test = compute_performance([best_estimator], X_test, y_test)
# # save to disk
# pickle.dump(score_dict_test, open(filename, 'wb'))
# load the model from disk
score_dict_test = pickle.load(open(filename, 'rb'))
df_score_test = pd.DataFrame(data=score_dict_test)
df_score_test.rename(columns={best_estimator.__class__.__name__: 'Test Set'}, inplace=True)
df_score_test
| Test Set | |
|---|---|
| accuracy | 0.837095 |
| auc | 0.837095 |
| f1 | 0.824117 |
| precision | 0.895451 |
| recall | 0.763310 |
filename = './score/score_train.csv'
# score_dict_train = compute_performance([best_estimator], X_train, y_train)
# # save to disk
# pickle.dump(score_dict_train, open(filename, 'wb'))
# load the model from disk
score_dict_train = pickle.load(open(filename, 'rb'))
df_score_train = pd.DataFrame(data=score_dict_train)
df_score_train.rename(columns={best_estimator.__class__.__name__: 'Train set'}, inplace=True)
df_score_train
| Train set | |
|---|---|
| accuracy | 0.869942 |
| auc | 0.869942 |
| f1 | 0.858618 |
| precision | 0.940506 |
| recall | 0.789848 |
df_merged = pd.concat([df_score_test, df_score_train], axis=1)
ax = df_merged.plot(kind='bar', rot=0)
ax.set_ylabel('Metriche di performance')
ax.set_xlabel('classificatori')
ax.set_title('Performance dei classificatori')
plt.legend(loc="lower center")
for p in ax.containers:
ax.bar_label(p, label_type="edge", labels=[f"{v:.1%}" for v in p.datavalues], fontsize=12)
plt.show()
I risultati mostrano il valore di accuracy sul test set pari a 83,7%, mentre sul training set pari a 87,0%, da ciò si evince che non è presente overfitting. Inoltre anche le altre misure calcolate sul test set non si discostano molto dalle performance sul training set.
Da notare che il valore di recall pari a 76,3% è più basso rispetto al valore di precision pari a 89,5%: ciò mette in evidenza che il modello ottenuto è più preciso e meno sensibile, significa che quando il modello predice che un incidente è grave, ha una maggiore probabilità di essere corretto rispetto a quando predice che un incidente sia lieve.
Tuttavia, ciò può anche significare che il modello rischia di perdere alcuni casi di incidenti gravi, classificandoli erroneamente come lievi.
In generale, dipende dal contesto e dello scopo del modello: ad esempio se l'obiettivo è quello di rilevare in tempo reale in base alle features dell'incidente se questo è grave o lieve, in modo da avvisare i soccorsi con diversi livelli di priorità di intervento sul posto.
Se il contesto quindi è quello appena descritto, e l'obiettivo è quello di minimizzare le risorse (soccorsi), in modo da evitare la loro saturazione, limitando il loro intervento su altri incidenti; allora il modello si comporterebbe bene perchè avendo un valore di precision più elevato del valore di recall, si avrà una maggiore probabilità che gli incidenti lievi verranno classificati come gravi (quindi evitare di occupare risorse inutilmente dato che in realtà l'incidente è lieve).
In conclusione i risultati ottenuti sono soddisfacenti.
Questo task di data mining ha visto una prima parte abbastanza corposa sull'analisi dei dati e sulla loro visualizzazione, ed una seconda parte di predizione dell'attributo target preceduto da tutta la fase di preprocessing dei dati. Inoltre si è visto come, tornando indietro nel ciclo di elaborazione, si sono ottenuti migliori risultati; infatti la fase successiva alla model selection è stata quella di rieseguire gli algoritmi di data mining, applicando ai dati una differente tecnica di undersampling per le classi sbilanciate. In definitiva si è scelto il miglior algoritmo sulla base di un validation set, e si sono calcolate le performance sul test set, tenuto in disparte dall'inizio dell'elaborazione del task. Un'ultima precisazione va fatta, il trade-off tra qualità della soluzione e tempo di esecuzione è molto importante. Avendo un dataset con una dimensione abbastanza considerevole, non tutti gli algoritmi avevano un basso tempo di esecuzione, soprattutto se all'interno di una GridSearch (anche per tale ragione si sono utilizzati pochi parametri). Inoltre, anche la fase di preprocessing attraverso i diversi step racchiusi nelle pipeline erano abbastanza lenti. Per tali motivazioni, si è deciso di eseguire gli algoritmi una sola volta e salvare i risultati su disco, così che nella successiva esecuazione essi potranno essere caricati direttamente da disco, riducendo drasticamente i tempi di esecuzione.
Per concludere, l'output finale di tale task può essere la seguente pipeline: full_pipeline prende in input un qualsiasi dato nella forma iniziale non pre elaborato, e restituisce la predizione effettuata sull'attributo target Accident_Severity.
full_pipeline = Pipeline([
('pre-processing', full_pipeline_test),
('classifier', best_estimator),
])